给几天前的打包器改了改,现在更好了(高级玩法:制作安装程序)

```js
/**

  • Nodejs File Pack Help by cmd1152

  • 开源许可证:MIT


  • node pack /files some_file.txt /output some_file.bat

  • /files [file1] <file2> … 传入要被嵌入的文件

  • /dir <dir> 传入目录结构,不常用,现在会自动检测叶子目录

  • /output [file_name] 要输出的批处理文件

  • /run [cmd] 附加命令到文件,一般用于释放后执行程序

  • /del 批处理执行完毕后删除自己

  • 一些高级玩法


    • 安装程序
  • node pack /files A /output A.bat /run A\setup

  • 这是 A 文件夹的目录结构

  • A\

  •    APP_NAME\
    
  •        setup.bat // 调用 setup_ink 释放快捷方式,下一级是文件内容
                @echo off
                cd "%~dp0"
    
                start /w "" "setup_ink.vbs"
                start mshta vbscript:msgbox("MY APP installation completed successfully",64,"MY APP")(window.close)
                del setup_ink.vbs
                del "%~0" &amp; exit
    
  •        shell.bat // 调用入口
    
  •        ink.ico // 快捷方式图标
    
  •        setup_ink.vbs //释放快捷方式,下一级是文件内容
                Set objShell = CreateObject("WScript.Shell")
                currentDir = objShell.CurrentDirectory
    
                targetPath = currentDir &amp; "\shell.bat"
                iconPath = currentDir &amp; "\ink.ico"
    
                desktopPath = objShell.SpecialFolders("Desktop") &amp; "\My APP.lnk"
    
                Set shortcut = objShell.CreateShortcut(desktopPath)
    
                shortcut.TargetPath = targetPath
                shortcut.WorkingDirectory = currentDir
                shortcut.IconLocation = iconPath
                shortcut.Save
    
  •        ... // 其他文件
    
  •    setup.bat // 用于复制文件到安装目录下,然后运行里面的 setup.bat 进一步安装,下一级是文件内容
           @echo off
           cd "%~dp0"
           echo;D|xcopy /Y /E APP_NAME "%HOMEDRIVE%%HOMEPATH%\APP_NAME"
    
           set "a=%cd%"
    
    
           cd /d "%HOMEDRIVE%%HOMEPATH%\APP_NAME"
           start "" "setup.bat"
    
           cd "%a%"
           cd ..
           rd /s /q "A" &amp; exit
    
  • 然后按照命令构建,得到一个bat文件

    构建开始
      树形扫描展开中
        已展开:
          叶子目录:
            A\APP_NAME
          文件:
            A\APP_NAME\ink.ico
            A\APP_NAME\shell.bat
            A\APP_NAME\setup.bat
            A\APP_NAME\setup_ink.vbs
            A\APP_NAME\setup.bat
            ...
      构建文件中
        Packing - A\APP_NAME\ink.ico
          转换cab - A\APP_NAME\ink.ico
        ...
      正在保存 A.bat
    构建完成
    
  • 在一个新环境双击,可以发现桌面多了个快捷方式,这就是安装成功了
    */

const fs = require(‘fs’);
const path = require(‘path’);
const { exec } = require(‘child_process’);

const argv = process.argv.slice(2);

const args = {};

argv.forEach((arg, index) => {
if (arg.startsWith(“/”)) {
let endIndex = argv.slice(index + 1).findIndex((arg) => arg.startsWith(‘/’)) + 1;
endIndex = endIndex == 0 ? undefined : index + endIndex;
args[arg.substring(1)] = argv.slice(index + 1, endIndex);
}
});

if (!args.files || args.files.length == 0) {
console.error(缺少 /files 指定需要嵌入的文件);
process.exit(1);
}
if (!args.output) {
console.error(缺少 /output 指定需要输出的文件);
process.exit(1);
}
if (!args.output[0].toLowerCase().endsWith(‘.bat’) && !args.output[0].toLowerCase().endsWith(‘.cmd’)) {
console.error(/output 文件必须是批处理格式);
process.exit(1);
}
if (args.files && args.files.some((filepath) => filepath.includes(“/”))) {
console.error(你似乎在使用 / 作为路径分割符号,请修改为 \\);
process.exit(1);
}
if (!args.dir && (args.files && args.files.some((filepath) => filepath.includes(“\”)))) {
console.error(你没有使用 /dir 创建目录树,但是在文件路径使用了路径符号,如果你希望打包目录,请直接写进去目录名\n也可能是你使用的路径不是相对路径导致的错误);
process.exit(1);
}

function readDirectory(dir, parentPath = ‘’, result = ) {
const fullPath = path.join(parentPath, dir);
const items = fs.readdirSync(fullPath);

let isLeaf = true;
items.forEach(item => {
const itemPath = path.join(fullPath, item);
const stats = fs.statSync(itemPath);
if (stats.isDirectory()) {
isLeaf = false;
readDirectory(item, fullPath, result);
}
});

if (isLeaf) {
result.push(fullPath.replace(///g, ‘\’));
}

return result;
}

async function readDirectoryRecursively(dir) {
const filePaths = ;

try {
const files = fs.readdirSync(dir, { withFileTypes: true });

for (const file of files) {
  const filePath = path.join(dir, file.name);
  if (file.isDirectory()) {
    const subDirPaths = await readDirectoryRecursively(filePath);
    filePaths.push(...subDirPaths);
  } else {
    filePaths.push(filePath.replace(/\//g, '\\'));
  }
}

} catch (err) {
console.error( 无法读取目录 ${dir}: ${err});
}

return filePaths;
}

async function makeBase64(file) {
console.log( Packing - ${file});

const cabFilePath = path.join(path.dirname(file), ${path.basename(file)}.cab);
await createCab(file, cabFilePath);

let data = fs.readFileSync(cabFilePath);
let b64 = data.toString(‘base64’);

fs.unlinkSync(cabFilePath);

return makeUnzip(b64, file);
}

async function createCab(filePath, cabFilePath) {
return new Promise((resolve, reject) => {
console.log( 转换cab - ${filePath});
const command = makecab "${filePath}" "${cabFilePath}";

exec(command, (error, stdout, stderr) =&gt; {
  if (error) {
    reject(new Error(`makecab failed: ${error.message}\n${stderr}`));
  } else {
    resolve(stdout);
  }
});

});
}

function makeUnzip(b64, filepath) {
return [
(,
b64.split(/(\n|.{1,3000})/).filter(d => d).map((line) => echo;${line}).join(“\r\n”),
)&gt;"${filepath.replace(/"/g, '\\"')}.b64",
IF EXIST "${filepath.replace(/"/g, '\\"')}" del "${filepath.replace(/"/g, '\\"')}",
certutil -decode "${filepath.replace(/"/g, '\\"')}.b64" "${filepath.replace(/"/g, '\\"')}.tmp" &gt; nul,
IF NOT EXIST "${filepath.replace(/"/g, '\\"')}.tmp" echo;Failed to Create ${filepath},
expand "${filepath.replace(/"/g, '\\"')}.tmp" "${filepath.replace(/"/g, '\\"')}" &gt;nul,
del "${filepath.replace(/"/g, '\\"')}.b64",
del "${filepath.replace(/"/g, '\\"')}.tmp",
].join(“\r\n”);
}

async function main() {
console.log(构建开始);
let packed = [
@echo off’,
];

console.log( 树形扫描展开中);
let file = ‘’;
let tf = ;
while (file = args.files.shift()) {
if (fs.statSync(file).isDirectory()) {
let n_files = await readDirectoryRecursively(file) || ;
let n_dirs = await readDirectory(file) || ;
console.log([
已展开:,
叶子目录:,
${n_dirs.join('\n ')},
文件:,
${n_files.join('\n ')},
].join(“\n”));

  tf = [...tf, ...n_files];
  args.dir = [...(args.dir || []), ...n_dirs];
} else tf.push(file);

};

if (args.dir) packed.push(md ${args.dir.map((d) =&gt; “${d.replace(/”/g, ‘\"’)}").join(" ")});

console.log( 构建文件中);
while (file = tf.shift()) {
let data = await makeBase64(file);
packed.push(data);
};

if (args.run) {
args.run.forEach((r) => {
packed.push(start "" "${r.replace(/"/g, '\\"')}");
});
}
if (args.del) packed.push(del "%~0");
console.log( 正在保存 ${args.output[0]});
fs.writeFileSync(args.output[0], packed.join(“\r\n”), { encoding: ‘latin1’ });
console.log(构建完成);
}

main();
```

是的,现在用了微软Windows自带的 cap 工具压缩了打包后文件的大小,而且是windows自带
也是不需要再安装什么新东西

然后帮助我写js代码里了,这样子方便看

打包成 GUI 的 exe,才能造福人类

@“James”#p209652 只需要直接写个exe扔 /run 参数里就可以

@“James”#p209652

[upl-file uuid=3cc29efc-193e-4e10-8d82-a330fc9ba784 size=27kB]www.zip[/upl-file]

@“James”#p209652 草,理解错了,我以为你说的是这个安装程序,如果写gui的话……

可以不试试 elecrtron ,然后转成 exe


***

4楼的压缩包看了吗,评价一下