问题:electron 中集成 nestjs 无法将 nestjs 的核心依赖从 dependencies 移除
“dependencies”中只保留核心模块的依赖,其他移入到"devDependencies"中,以减少打包体积,如:
"dependencies": {
"better-sqlite3": "^11.8.1",
"better-sqlite3-multiple-ciphers": "^11.8.1",
"typeorm": "^0.3.21",
"reflect-metadata": "^0.2.2",
"@nestjs/core": "^11.1.5",
"@nestjs/common": "^11.1.5",
"@nestjs/platform-express": "^11.1.5",
"rxjs": "^7.8.2"
},
非 nestjs 框架,只保留前面 4 个依赖即可。
files:
- '!**/.vscode/*'
- '!src/*'
- '!electron.vite.config.{js,ts,mjs,cjs}'
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
- '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}'
- '!store/*'
- '!*.md'
- '!log/*'
- '!dist/**'
- '!locales/**'
- '!dist/win-unpacked'
- '!data/*'
- '!node_modules/.vite/**'
- '!node_modules/@opentiny/**' # 不打包tiny的组件
- '!node_modules/@swc/**' # 编译ts的插件
- '!node_modules/better-sqlite3'
- '!node_modules/better-sqlite3-multiple-ciphers'
- '!node_modules/hyt-exam-native/*'
- '!node_modules/typeorm/*'
- '!packages'
- '!resources/*'
extraResources:
- from: 'resources'
to: 'resources'
- from: 'node_modules/better-sqlite3'
to: 'node_modules/better-sqlite3'
- from: 'node_modules/better-sqlite3-multiple-ciphers'
to: 'node_modules/better-sqlite3-multiple-ciphers'
- from: 'packages/hyt-exam-native'
to: 'node_modules/hyt-exam-native'
- from: 'node_modules/typeorm'
to: 'node_modules/typeorm'
import { initModulePathEval } from './build/scripts/module-path.js'
main: {
plugins: [externalizeDepsPlugin()],
build: {
chunkSizeWarningLimit: 2000,
assetsInlineLimit: 1024 * 2, // 2KB 以下图片转 Base64;设置大了转成base64后会增加包大小
// 在生产环境移除console.log
terserOptions: {
compress: {
drop_console: false,
pure_funcs: ['console.log', 'console.info'],
drop_debugger: true
}
},
rollupOptions: {
input: {
index: path.resolve(__dirname, 'src/main/index.ts')
},
output: {
banner: initModulePathEval // 打包时注入模块路径-核心
}
}
}
},
这一步,目前我也没看懂为啥这么做。 在根目录的 build 文件夹下创建 scripts 文件夹,并在该文件夹下创建 module-path.js 文件,内容如下:
export const initModulePathEval = `
// ================== early init start ==================
(function(){
const path = require('path')
const resourcesPath = process.resourcesPath
const resourceModules = path.join(resourcesPath, 'node_modules')
const asarModules = path.join(resourcesPath, 'app.asar', 'node_modules')
const extraPaths = [resourceModules, asarModules]
const isWindows = process.platform === 'win32'
// 把 extraResources 和 asar 的 node_modules 添加到搜索路径
process.env.NODE_PATH = extraPaths.join(isWindows ? ';' : ':')
require('module').Module._initPaths()
})();
// ================== early init end ==================
`
package-lock.json 不能忽略提交,不然只能在一台电脑打包更新,其他电脑打包更新会报错。
import { spawn } from 'node:child_process'
return new Promise((resolve) => {
const child = spawn(exePath, ['--uv', v], {
detached: true,
stdio: 'ignore',
windowsHide: true
}) as any
child.unref()
timer = setTimeout(() => {
child.kill() // 2s后杀死子进程
}, 2000)
app.quit() //立即退出程序,避免asar被占用
child.on('error', (error) => {
// 更新失败
return resolve(0)
})
resolve(1) // 更新成功
})
@echo off
:: echo 开始执行文件操作...
:: 检查history文件夹是否存在,不存在则创建
if not exist "history" (
mkdir "history"
echo 创建history文件夹成功
)
:: 检查app.asar是否存在,如果存在则移动并重命名
if exist "app.asar" (
move "app.asar" "history\4.25.16.asar" >nul
)
:: 检查pack.asar是否存在,如果存在则重命名为app.asar
if exist "pack.asar" (
ren "pack.asar" "app.asar"
)
自研“退出-替换-重启”小脚本
const { app } = require('electron')
const path = require('path')
const fs = require('fs-extra')
const cp = require('child_process')
const ASAR = path.join(__dirname, '../app.asar')
const TMP = path.join(__dirname, '../app_new.asar')
// 1. 下载完新 asar 后把它重命名为 app_new.asar
// 2. 启动一个 detached 的“替换器”
function applyUpdate() {
const bat = path.join(__dirname, 'updater.exe') // 也可以直接写 .bat
// updater.exe 内容见下
cp.spawn(bat, [process.pid, TMP, ASAR], {
detached: true,
stdio: 'ignore'
}).unref()
app.quit() // 主进程立即退出,释放句柄
}
// updater.exe(C++ / Go / PyInstaller 均可)逻辑:
// ① 等待父进程 PID 消失;
// ② MoveFileEx(app_new.asar, app.asar, MOVEFILE_REPLACE_EXISTING);
// ③ ShellExecute 原 exe 路径,重启 App。
签名丢失:只要替换了 asar,Windows 重新计算哈希,Mac 会破环签名,上架商店版本必须走全量安装器; 不要把新文件命名为 app.asar.tmp 后原地改名——改名瞬间同样会被锁;
全部排除方式
asar 最轻量化,最优解
electron-builder.yml 中配置如下:
# 以下不打包进asar
asarUnpack:
- node_modules/** #【重要】所有node_modules目录不打包进asar
- resources/** #resources目录不打包进asar
- node_modules/better-sqlite3
- node_modules/better-sqlite3-multiple-ciphers