关于使用pkg打包node项目为exe可执行文件,内含命令行执行代码不可执行问题定位说明

近期有朋友请教我一个问题,为何他将node项目打包成exe文件之后,他的项目就运行不正常了,也就是需要播放一段音频。他的代码如下

项目工程代码查看

const http = require("http");
const sound = require("sound-play");
const path = require("path");
const fs = require("fs");
const filePath = path.join(__dirname, "./dist/alert.mp3");

const server = http.createServer((req, res) => {
    
    
    res.writeHead(200, {
    
     "Content-Type": "text/plain;charset=utf-8" });
    res.end("测试音频播放\n");
    sound.play(filePath);
});

server.listen(8000, () => {
    
    
    console.log("Server running at http://localhost:8000/");
});

这段代码我们看下来也没啥问题,无非就是起了一个端口为8000的http服务,当用户访问这个服务接口时,就会发送消息给客户端,同时后端进行音频播放操作。

在然后我们看下pkg 打包成可执行exe 命令有没有问题,通过查看 package.json,我们看下完整配置

{
    
    
  "name": "alert",
  "bin": "./index.js",
  "scripts": {
    
    
    "pkg": "pkg . -d -t node16-win-x64   -o",
    "start": "node index.js"
  },
  "pkg": {
    
    
    "assets": [
      "dist/**/*"
    ]
  },
  "dependencies": {
    
    
    "sound-play": "^1.1.0"
  }
}

大致从这里我们也看到了 pkg 命令参数,是以 node16-win-x64 为目标环境编译的exe 文件,但是很神奇,看似没问题的地方,运行起来,音频就是没有播放。

sound-play 库源码分析(注意这里是我添加了日志,方便定位的)

const {
    
     exec } = require("child_process");
const fs = require("fs");

const execPromise = require("util").promisify(exec);

/* MAC PLAY COMMAND */
const macPlayCommand = (path, volume) => `afplay \"${
      
      path}\" -v ${
      
      volume}`;

/* WINDOW PLAY COMMANDS */
const addPresentationCore = `Add-Type -AssemblyName presentationCore;`;
const createMediaPlayer = `$player = New-Object system.windows.media.mediaplayer;`;
const loadAudioFile = (path) => `$player.open('${
      
      path}');`;
const playAudio = `$player.Play();`;
const stopAudio = `Start-Sleep 1; Start-Sleep -s $player.NaturalDuration.TimeSpan.TotalSeconds;Exit;`;

const windowPlayCommand = (path, volume) =>
    `powershell -c ${
      
      addPresentationCore} ${
      
      createMediaPlayer} ${
      
      loadAudioFile(
        path
    )} $player.Volume = ${
      
      volume}; ${
      
      playAudio} ${
      
      stopAudio}`;

module.exports = {
    
    
    play: async (path, volume = 0.5) => {
    
    
        /**
         * Window: mediaplayer's volume is from 0 to 1, default is 0.5
         * Mac: afplay's volume is from 0 to 255, default is 1. However, volume > 2 usually result in distortion.
         * Therefore, it is better to limit the volume on Mac, and set a common scale of 0 to 1 for simplicity
         */
        try {
    
    
            const volumeAdjustedByOS =
                process.platform === "darwin"
                    ? Math.min(2, volume * 2)
                    : volume;

            const playCommand =
                process.platform === "darwin"
                    ? macPlayCommand(path, volumeAdjustedByOS)
                    : windowPlayCommand(path, volumeAdjustedByOS);
            fs.appendFile(
                "./log.txt",
                `${
      
      new Date().toLocaleString()},${
      
      playCommand}\n`,
                (error) => {
    
    }
            );
            fs.appendFile(
                "./log.txt",
                `${
      
      new Date().toLocaleString()},开始音频播放\n`,
                (error) => {
    
    }
            );

            await execPromise(playCommand);
        } catch (err) {
    
    
            fs.appendFile(
                "./log.txt",
                `${
      
      new Date().toLocaleString()},${
      
      err}\n`,
                (error) => {
    
    }
            );
            throw err;
        }
    },
};

从上述代码,我们知道这里的核心原理便是利用powershell 调用系统的播放器进行音频的播放,这里我们就知道不能调用的原因了,因为一个exe文件调用powershell 是有安全策略问题的, 自然不能正常调用。

转换思路,既然这个行不通,那我们最简单的方式,可以写bat脚本呀,也是双击操作

start cmd /k "cd  node完整工程目录 && npm run start"

以上就是一段简单的分析了,其实分析过程中,日志的打印也是蛮关键的,我在上述排除问题中,其实除了发现是powershell 无法调用,还有一个就是当我们打包成exe可执行文件之后,那么__dirname 获取到的路径是虚拟的,这也导致即使我们放开了安全策略,也会无法调用,因为虚拟路径在powershell 中是访问不到的。这个时候我们可以采用相对路径的方式 即把 path.join(__dirname, "./dist/alert.mp3") 方法 改成path.resolve("./dist/alert.mp3");相对路径即可。

猜你喜欢

转载自blog.csdn.net/weixin_39370315/article/details/129959633
今日推荐