electron 不知道为什么用不了 node-pty
目前找到的解决方法是用 child_process.fork() 创建子进程,在子进程里运行 node-pty
由于electron 引入node-pty报错,且 asar 不能打包 node-pty ,所以动态载入 import(“node-pty”)
核心方法
import { Pty客户端_Fork } from "...../服务端_pty终端.mjs"
let 子进程脚本路径 = "...../服务端_pty终端.mjs"
const pty终端 = new Pty客户端_Fork(子进程脚本路径)
pty终端.spawn( "bash", [], { //打开 bash 终端
name:'xterm-256color' , //配色名必须是 xterm-256color //echo $TERM xterm-256color 配色
env:process.env,
cwd:窗口启动信令.工作目录 || os.homedir() ,
指令:窗口启动信令.指令 || ""
})
pty终端.onData(data=>{ })
服务端_pty终端.mjs ------------- 脚本 如下
/*
------ 子进程脚本 -------------------------------
此脚本作为子进程运行(被 fork 调用) 不能被 asar 压缩 !!!
此脚本和它的父进程 IPC通信 process.send process.on
*/
import child_process from "child_process"
export { Pty客户端_Fork }
// pty 用原生 send 发送信令 并未包装
class Pty客户端_Fork{ // 为什么封装 pty , 因为electron 不支持 这类模块 Error:Loading non-context-aware native module in renderer:
constructor(pty服务进程脚本路径){
this.fork进程 = child_process.fork( pty服务进程脚本路径 , {execArgv:process.execArgv })
this.pid = this.fork进程.pid
this.onPty退出((err)=>{console.log(err)}) //监控状态
}
onPty退出(回调函数){
this.fork进程.addListener("error", err=>{ 回调函数({类型:"pty终端 fork子进程error",数据:err}) })
this.fork进程.addListener("close", ()=>{ 回调函数({类型:"pty终端 fork子进程close",数据:this.js脚本路径}) })
this.fork进程.addListener("exit", ()=>{ 回调函数({类型:"pty终端 fork子进程exit" }) })
this.fork进程.addListener("disconnect", ()=>{ 回调函数({类型:"pty终端 fork子进程disconnect" }) })
this.onExit( (err)=>回调函数({类型:"pty终端主动退出",数据:err}) )
}
kill(){ this.fork进程.send({类型:"kill"}) ; this.fork进程.kill() }
write(字符串){ this.fork进程.send({类型:"write", 数据: 字符串}) }
spawn(file, args, options){ this.fork进程.send({类型:"spawn", 数据:{file: file, args:args, options:options }} ) }
resize(columns,rows){ this.fork进程.send({类型:"resize", 数据:{columns: columns, rows:rows }} ) }
onData(回调函数){ this.fork进程.addListener("message",信令=>{ if(信令.类型==="onData") 回调函数(信令.数据) }) }
onExit(回调函数){ this.fork进程.addListener("message",信令=>{ if(信令.类型==="onExit") 回调函数(信令.数据) }) }
}
//服务端
class pty服务端{
constructor(){
this.终端
}
async spawn(file, args , options){
try{ // 主进程里引入 node-pty 报错 只能动态引入
const pty = await import("node-pty")
this.终端 = pty.spawn(file, args , options )
this.__proto__.__proto__= this.终端 //继承了所有方法 这里的 spawn 优先执行
}catch(err){
process.send({类型:"onExit", 数据:{来源:"pty.spawn() 启动失败", err:err}})
}
}
}
//================ 如果是子进程 运行服务端 ==================
if(process?.send || process?.parentPort ){ //child_process / electron UtilityProcess
const pty终端 = new pty服务端() // 可以看作只修改了spawn方法原 pty
const 同步信令处理表={
"spawn":async 数据=>{
//创建进程
await pty终端.spawn(数据.file, 数据.args , 数据.options ) //打开 bash 终端 配色名必须是 xterm-256color //echo $TERM xterm-256color 配色
pty终端.onData( data=>{ process.send({类型:"onData", 数据:data }) }) //🌷🌷🌷
pty终端.onExit( err=>{ process.send({类型:"onExit", 数据:err}) })
//运行传入指令
if(数据.options.指令) setTimeout(()=>{ pty终端.write(`${数据.options.指令}\n`) } ,50)
},
"write":数据=>{ pty终端.write(数据) },
"kill":数据=>{ pty终端.kill() ; process.exit() },
"resize":数据=>{ pty终端.resize(数据.columns,数据.rows) },
}
//child_process
process?.on?.("message", 信令=>{ 同步信令处理表[信令.类型]?.(信令.数据) }) //调用
process?.send?.("启动完成") // 向父进程 握手
}