1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- #!/usr/bin/env node
- import inquirer from 'inquirer'
- import { execSync } from 'child_process'
- import fs from 'fs'
- import { join } from 'path'
- import { tmpdir } from 'os'
- import archiver from 'archiver'
- import dayjs from 'dayjs'
- // ---------- 环境配置 ----------
- const ENV_CONFIG = {
- dev: { remoteUser: 'root', remoteIP: '192.168.2.140', remoteAppDir: '/work/web/dist' },
- test: { remoteUser: 'liujia', remoteIP: '43.137.10.199', remoteAppDir: '/work/web/dist' },
- prod: { remoteUser: 'root', remoteIP: '192.168.2.140', remoteAppDir: '/work/web/dist-prod' },
- }
- const SSH_PORT = 22
- const LOCAL_DIST = 'D:/project/ln-web/dist'
- // ---------- 处理环境参数 ----------
- let env = process.argv[2] // npm run deploy:dev 传入 dev/test/prod
- if (!env || !ENV_CONFIG[env]) {
- const answer = await inquirer.prompt([
- {
- type: 'list',
- name: 'env',
- message: '请选择要部署的环境:',
- choices: Object.keys(ENV_CONFIG),
- default: 'dev',
- },
- ])
- env = answer.env
- }
- const { remoteUser, remoteIP, remoteAppDir } = ENV_CONFIG[env]
- console.log(`\n你选择的环境是: ${env}, 远程目录: ${remoteAppDir}\n`)
- // ---------- 压缩 dist ----------
- const timestamp = dayjs().format('YYYYMMDDHHmmss')
- const zipFileName = `dist-${timestamp}.zip`
- const zipPath = join(tmpdir(), zipFileName)
- console.log('📦 正在压缩 dist...')
- if (!fs.existsSync(LOCAL_DIST)) {
- console.error(`❌ 本地 dist 目录不存在: ${LOCAL_DIST}`)
- process.exit(1)
- }
- await new Promise((resolve, reject) => {
- const output = fs.createWriteStream(zipPath)
- const archive = archiver('zip', { zlib: { level: 9 } })
- output.on('close', () => resolve())
- archive.on('error', (err) => reject(err))
- archive.pipe(output)
- archive.directory(LOCAL_DIST, false)
- archive.finalize()
- })
- const zipSizeMB = (fs.statSync(zipPath).size / 1024 / 1024).toFixed(2)
- console.log(`✅ 压缩完成: ${zipSizeMB} MB, 文件: ${zipPath}`)
- // ---------- 上传 & 部署脚本生成 ----------
- const remoteZip = `/tmp/dist-latest-${timestamp}.zip`
- execSync(`scp -P ${SSH_PORT} "${zipPath}" ${remoteUser}@${remoteIP}:${remoteZip}`, {
- stdio: 'inherit',
- })
- const remoteScriptContent = `#!/bin/bash
- set -e
- timestamp="${timestamp}"
- tmpdir="/tmp/dist-temp-$timestamp"
- target="${remoteAppDir}"
- zipfile="${remoteZip}"
- echo "📦 正在服务器上原子部署 ..."
- echo "📁 创建临时目录 $tmpdir"
- mkdir -p "$tmpdir"
- echo "📦 解压上传文件"
- unzip -qo "$zipfile" -d "$tmpdir"
- echo "🔒 设置权限"
- chown -R root:root "$tmpdir"
- echo "🚀 替换新目录"
- rm -rf "$target"
- mv "$tmpdir" "$target"
- echo "🧹 删除压缩包"
- rm -f "$zipfile"
- echo "✅ 远程部署完成: $target 替换成功"
- `
- const localScriptPath = join(tmpdir(), `deploy-temp-${timestamp}.sh`)
- fs.writeFileSync(localScriptPath, remoteScriptContent, { encoding: 'utf8' })
- const remoteScriptPath = `/tmp/deploy-temp-${timestamp}.sh`
- execSync(`scp -P ${SSH_PORT} "${localScriptPath}" ${remoteUser}@${remoteIP}:${remoteScriptPath}`, {
- stdio: 'inherit',
- })
- console.log('\n🚀 执行远程部署脚本...')
- execSync(`ssh -p ${SSH_PORT} ${remoteUser}@${remoteIP} "bash ${remoteScriptPath}"`, {
- stdio: 'inherit',
- })
- console.log('\n🧹 清理本地/远程临时文件...')
- fs.unlinkSync(zipPath)
- fs.unlinkSync(localScriptPath)
- execSync(`ssh -p ${SSH_PORT} ${remoteUser}@${remoteIP} "rm -f ${remoteScriptPath} ${remoteZip}"`, {
- stdio: 'inherit',
- })
- console.log(`\n✅ [${env}] 环境部署完成!`)
|