diff --git a/deploy.js b/deploy.js new file mode 100644 index 0000000..7c92b77 --- /dev/null +++ b/deploy.js @@ -0,0 +1,125 @@ +/** + * $description + * @author 一七年夏 + * @since 2022-12-07 14:00 + */ +'use strict' + +const childProcess = require('child_process') +const SSH2Promise = require('ssh2-promise') +const fs = require('fs') +const { v4 } = require('uuid') +const { zip } = require('compressing') +const dialog = require('dialog') +const delay = (ms) => new Promise((r) => setTimeout(r, ms)) + +const sshConfig = { + host: 'clould.lolosia.top', + port: 22, + username: 'lolosia', + password: 'lolo2024.' +} +const tempDir = '/home/lolosia/nginx/cache' +const tempPrefix = 'home' +const nginxContentPath = 'home' + +async function localExec(cmd) { + return new Promise((r, rj) => { + const process1 = childProcess.exec(cmd) + process1.on('exit', r) + process1.on('error', rj) + process1.stdout.pipe(process.stdout) + process1.stderr.pipe(process.stderr) + }) +} + +async function main() { + if (!process.argv.includes('-r')) { + console.log('项目构建...') + console.log('前端构建耗时较长,你可以去做其他事,稍后本脚本会弹窗提醒完成。') + await localExec('.\\node_modules\\.bin\\vite build --mode build') + console.log('构建zip...') + await zip.compressDir(`./dist`, './archive.zip') + console.log('连接至服务器...') + } else { + console.log('重新推送...') + } + const ssh2 = new SSH2Promise(sshConfig) + + await ssh2.connect() + const ftp = ssh2.sftp() + async function exec(cmd) { + console.log(`运行 ${cmd} ...`) + console.log(await ssh2.exec(cmd)) + } + async function sudo(cmd) { + const shell = await ssh2.shell() + shell.stdout.pipe(process.stdout) + shell.stderr.pipe(process.stderr) + process.stdin.pipe(shell.stdin) + shell.write(`sudo ${cmd}\n`) + await delay(500) + shell.write(`${sshConfig.password}\n`) + await delay(1000) + shell.write('exit\n') + await new Promise((resolve) => { + shell.on('end', resolve) + }) + process.stdin.unpipe(shell.stdin) + } + async function write(path, text) { + const stream = await ftp.createWriteStream(path, { encoding: 'utf-8' }) + return new Promise((r) => { + stream.write(text) + stream.end(r) + }) + } + const dir = tempDir + await exec(`mkdir -p ${dir}`) + const archivePath = `${dir}/archive.zip` + console.log(`删除 ${archivePath} ...`) + try { + await ftp.unlink(archivePath) + // eslint-disable-next-line no-empty + } catch (e) {} + console.log(`写入 ${archivePath} ...`) + const stream = await ftp.createWriteStream(archivePath, { + encoding: 'binary' + }) + const file = fs.createReadStream('./archive.zip', { + encoding: 'binary', + autoClose: true + }) + await new Promise((r, rj) => { + // file.on('close', () => stream.end()); + stream.on('finish', () => r()) + file.on('end', () => r()) + file.on('error', rj) + stream.on('error', rj) + file.pipe(stream) + }) + console.log(`写入 ${archivePath} 完成`) + const uuid = v4() + const target = `${dir}/${tempPrefix}-${uuid}` + //if (process.platform === 'win32') { + // await exec(`unzip -O gbk ${archivePath} -d ${target}`) + //} else { + await exec(`unzip ${archivePath} -d ${target}`) + await exec(`mv ${target}/dist ${target}/iGame`) + //} + + const nginxTarget = '/home/lolosia/nginx/home' + + console.log('移除旧目录 ...') + await sudo(`rm -rf ${nginxTarget}/${nginxContentPath}`) + + console.log('复制文件 到指定目录 ...') + await sudo(`cp -r -f ${target}/* ${nginxTarget}`) + await new Promise((r) => { + dialog.info(`你现在可以关闭终端,去做其他事情了`, `${nginxContentPath}项目部署完成!`, r) + }) +} + +main() + .catch((e) => console.error(e)) + .finally(() => process.exit(0)) diff --git a/package.json b/package.json index ea29d6a..954fae4 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,8 @@ "@vue/cli-service": "^5.0.8", "@vue/test-utils": "^2.4.5", "@vueuse/core": "^10.9.0", + "compressing": "^1.10.0", + "dialog": "^0.3.1", "ejs": "^3.1.9", "eslint": "^8.56.0", "eslint-config-prettier": "8.5.0", @@ -91,6 +93,7 @@ "resize-observer-polyfill": "^1.5.1", "rollup-plugin-visualizer": "^5.12.0", "sass": "^1.72.0", + "ssh2-promise": "^1.0.3", "svg-sprite-loader": "6.0.11", "terser": "^5.29.2", "typescript": "^5.4.3", diff --git a/vite.config.ts b/vite.config.ts index 2136b9a..6b98142 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,6 +1,6 @@ import { resolve } from 'path' import { ConfigEnv, defineConfig, loadEnv, ServerOptions, UserConfig } from 'vite' -import vue from '@vitejs/plugin-vue' +import vue, { parseVueRequest } from '@vitejs/plugin-vue' import vueJsx from '@vitejs/plugin-vue-jsx' import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' import { ViteMockOptions, viteMockServe } from 'vite-plugin-mock' @@ -94,13 +94,33 @@ export default defineConfig(({ command, mode }: ConfigEnv): UserConfig => { }), vitePluginSetupExtend({ inject: { title: setting.title } }), - vitePluginVueSetupExtend() + vitePluginVueSetupExtend(), //依赖分析插件 // visualizer({ // open: true, // gzipSize: true, // brotliSize: true // }) + + { + name: 'index-transform', + transform(code, id) { + const { filename } = parseVueRequest(id) + if (!filename.includes('vite/preload-helper')) return code + const fn = 'export const __vitePreload' + const index = code.indexOf(fn) + const head = code + .slice(0, index) + .split(';') + .map((it) => `${it};`) + const preload = code.slice(index) + const assetsURLIndex = head.findIndex((it) => it.startsWith('const assetsURL')) + let assetsURL = head[assetsURLIndex] + assetsURL = assetsURL.replace(' return ', " return (window.NGINX_BASE_URL || '') + ") + head[assetsURLIndex] = assetsURL + return [...head, preload].join('\n') + } + } ], build: { chunkSizeWarningLimit: 10000, //消除触发警告的 chunk, 默认500k