Tauri应用启动时运行node服务
准备工作:
- 将node打包成可执行的二进制文件
- 配置二进制运行文件:Tauri运行二进制文件
- 运行二进制文件: 运行二进制文件
在前端的启动文件中运行二进制文件启动项目
JavaScript
import { createApp } from 'vue'
// import VueRouter from 'vue-router'
import ArcoVue from '@arco-design/web-vue';
import './style.css'
import App from './App.vue'
import '@arco-design/web-vue/dist/arco.css';
import router from './router/index'
import { Command } from "@tauri-apps/api/shell";
//启动服务
async function server(){
const cm = Command.sidecar("bin/server",['start'])
const v = await cm.execute();
console.log(v.stderr)
}
const app = createApp(App)
app.use(ArcoVue);
// app.use(VueRouter)
app.use(router);
server().then(res=>{
console.log("server start")
})
app.mount('#app')
扩展阅读
我们通过上面的代码在dev 模式下server其实是会重复执行的,如果node程序没有做兼容的话就会导致端口被占用
我们应该怎么解决呢?
- 第一种方式:我们可以将之前的端口kill
JavaScript
const Koa = require('koa');
const Router = require('koa-router')
const cors = require('koa2-cors');
const bodyParser = require('koa-bodyparser')
const apiRouter = require('./api')
const { spawn, exec } = require('child_process');
const app = new Koa()
const router = new Router()
app.use(cors());
app.use(bodyParser())
router.get("/", (ctx) => ctx.body = "hello ")
router.get('/getData', (ctx) => {
ctx.body = {
code: 0,
data: {
name: 'zhangsan',
age: 18
}
}
});
// 注册路由
app.use(router.routes())
router.use('/api', apiRouter.routes(), apiRouter.allowedMethods())
// 自动丰富 response 相应头
app.use(router.allowedMethods())
async function stopPreviousServer(port) {
try {
// 查询当前端口的pid
const { stdout, stderr } = await exec(`lsof -i :${port} | grep LISTEN | awk '{print $2}'`);
let pids = '';
stdout.on('data', (data) => {
pids += data.toString();
});
stdout.on('end', () => {
pids = pids.trim().split('\n'); // 将 stdout 转换为字符串并进行操作
pids.forEach(pid => {
// 通过pid关闭端口
exec(`kill ${pid}`, (error, stdout, stderr) => {
if (error) {
console.error(`Failed to stop server (PID: ${pid}): ${error.message}`);
} else {
console.log(`Server stopped (PID: ${pid}): ${stdout}`);
}
});
});
});
} catch (error) {
console.error('Failed to retrieve running server processes:', error);
}
}
// 检查端口是否被占用
function isPortTaken(port) {
return new Promise((resolve, reject) => {
const net = require('net');
const tester = net.createServer()
.once('error', (err) => {
if (err.code === 'EADDRINUSE') {
resolve(true);
} else {
reject(err);
}
})
.once('listening', () => {
tester.once('close', () => resolve(false)).close();
})
.listen(port);
});
}
async function startServer(port) {
const portTaken = await isPortTaken(port);
if (portTaken) {
console.log(`Port ${port} is taken. Stopping existing process...`);
await stopPreviousServer(port); // 停止先前的服务器进程
}
setTimeout(() => {
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
}, 1000); // Wait for 1 second before starting the server
}
const action = process.argv[2];
const port = 3000;
if (action === 'start') {
startServer(port);
} else if (action === 'stop') {
stopPreviousServer(port)
console.log('Stop action is not supported in this version.'); // 不再需要停止服务器,因为新的服务器会自动停止先前的服务器
} else {
startServer(port);
console.error('Invalid action. Please use "start" or "stop".');
}
- 第二种方式:如果端口已经被占用了,启动新的端口
JavaScript
async function startServer(port) {
const portTaken = await isPortTaken(port);
let newPort = port;
if (portTaken) {
console.log(`Port ${port} is taken. Stopping existing process...`);
// 开启新的端口
newPort++;
}
setTimeout(() => {
app.listen(port, () => {
console.log(`Server is running on port ${newPort}`);
});
}, 1000); // Wait for 1 second before starting the server
}
- 第三种方式:如果项目已经启动了这个时候我们就不重新启动项目了
JavaScript
async function startServer(port) {
const portTaken = await isPortTaken(port);
let newPort = port;
if (portTaken) {
return;
}
setTimeout(() => {
app.listen(port, () => {
console.log(`Server is running on port ${newPort}`);
});
}, 1000); // Wait for 1 second before starting the server
}