Skip to content

Tauri应用启动时运行node服务

准备工作:

  1. 将node打包成可执行的二进制文件
  2. 配置二进制运行文件:Tauri运行二进制文件
  3. 运行二进制文件: 运行二进制文件

在前端的启动文件中运行二进制文件启动项目

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程序没有做兼容的话就会导致端口被占用

img

我们应该怎么解决呢?

  1. 第一种方式:我们可以将之前的端口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".');
}
  1. 第二种方式:如果端口已经被占用了,启动新的端口
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
}
  1. 第三种方式:如果项目已经启动了这个时候我们就不重新启动项目了
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
}

前端知识体系 · wcrane