From c832c0274a02b63b1ffd4285a0286eb5373ec821 Mon Sep 17 00:00:00 2001 From: xion Date: Mon, 21 Oct 2024 01:36:34 +0800 Subject: [PATCH] feat: add vite dev containers --- apps/.gitignore | 1 + apps/package.json | 13 ++ package.json | 3 +- pnpm-lock.yaml | 309 +++++++++++++++++++++++++++++++++++++++ src/app.ts | 22 ++- src/command/config.ts | 35 ++++- src/command/login.ts | 2 +- src/command/router.ts | 52 +++++++ src/command/web.ts | 71 +++++++++ src/index.ts | 2 + src/module/get-config.ts | 15 +- src/module/run-vite.ts | 79 ++++++++++ 12 files changed, 590 insertions(+), 14 deletions(-) create mode 100644 apps/.gitignore create mode 100644 apps/package.json create mode 100644 src/command/router.ts create mode 100644 src/command/web.ts create mode 100644 src/module/run-vite.ts diff --git a/apps/.gitignore b/apps/.gitignore new file mode 100644 index 0000000..50208cb --- /dev/null +++ b/apps/.gitignore @@ -0,0 +1 @@ +container \ No newline at end of file diff --git a/apps/package.json b/apps/package.json new file mode 100644 index 0000000..5edf761 --- /dev/null +++ b/apps/package.json @@ -0,0 +1,13 @@ +{ + "name": "apps", + "version": "1.0.0", + "description": "", + "main": "index.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/package.json b/package.json index 9e0cde6..7b2549f 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "@kevisual/router": "^0.0.2", "pg-hstore": "^2.3.4", "sequelize": "^6.37.4", - "sqlite3": "^5.1.7" + "sqlite3": "^5.1.7", + "vite": "^5.4.9" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 107626c..4384fd8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: sqlite3: specifier: ^5.1.7 version: 5.1.7 + vite: + specifier: ^5.4.9 + version: 5.4.9(@types/node@22.5.5) devDependencies: '@kevisual/query': specifier: 0.0.7-alpha.1 @@ -72,6 +75,144 @@ importers: packages: + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + '@gar/promisify@1.1.3': resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} @@ -496,6 +637,11 @@ packages: err-code@2.0.3: resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} @@ -753,6 +899,11 @@ packages: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} + nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + napi-build-utils@1.0.2: resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} @@ -818,10 +969,17 @@ packages: resolution: {integrity: sha512-N3SGs/Rf+xA1M2/n0JBiXFDVMzdekwLZLAO0g7mpDY9ouX+fDI7jS6kTq3JujmYbtNSJ53TJ0q4G98KVZSM4EA==} engines: {node: '>= 0.8.x'} + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picomatch@4.0.2: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} + postcss@8.4.47: + resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} + engines: {node: ^10 || ^12 || >=14} + prebuild-install@7.1.2: resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} engines: {node: '>=10'} @@ -967,6 +1125,10 @@ packages: resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} @@ -1060,6 +1222,37 @@ packages: resolution: {integrity: sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==} engines: {node: '>= 0.10'} + vite@5.4.9: + resolution: {integrity: sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -1107,6 +1300,75 @@ packages: snapshots: + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + '@gar/promisify@1.1.3': optional: true @@ -1554,6 +1816,32 @@ snapshots: err-code@2.0.3: optional: true + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + estree-walker@2.0.2: {} expand-template@2.0.3: {} @@ -1848,6 +2136,8 @@ snapshots: mute-stream@2.0.0: {} + nanoid@3.3.7: {} + napi-build-utils@1.0.2: {} negotiator@0.6.3: @@ -1920,8 +2210,16 @@ snapshots: dependencies: underscore: 1.13.7 + picocolors@1.1.1: {} + picomatch@4.0.2: {} + postcss@8.4.47: + dependencies: + nanoid: 3.3.7 + picocolors: 1.1.1 + source-map-js: 1.2.1 + prebuild-install@7.1.2: dependencies: detect-libc: 2.0.3 @@ -2085,6 +2383,8 @@ snapshots: smart-buffer: 4.2.0 optional: true + source-map-js@1.2.1: {} + sprintf-js@1.1.3: optional: true @@ -2193,6 +2493,15 @@ snapshots: validator@13.12.0: {} + vite@5.4.9(@types/node@22.5.5): + dependencies: + esbuild: 0.21.5 + postcss: 8.4.47 + rollup: 4.24.0 + optionalDependencies: + '@types/node': 22.5.5 + fsevents: 2.3.3 + which@2.0.2: dependencies: isexe: 2.0.0 diff --git a/src/app.ts b/src/app.ts index 634725f..761b610 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,6 +1,6 @@ import { App } from '@kevisual/router'; import fs from 'fs'; -import { getConfig, pidFilePath, checkFileExists } from './module/get-config.ts'; +import { getConfig, getPidList, pidFilePath, checkFileExists } from './module/get-config.ts'; import { sequelize } from './module/sequelize.ts'; export { sequelize }; @@ -28,11 +28,21 @@ app // 处理进程退出或中断信号,确保删除 pid 文件 const cleanUp = () => { - if (checkFileExists(pidFilePath)) { - const pid = fs.readFileSync(pidFilePath, 'utf-8'); - if (Number(pid) === process.pid) { - fs.unlinkSync(pidFilePath); - console.log('server id', process.pid, 'is exit'); + const pidList = getPidList(); + const findPid = pidList.find((item) => Number(item.pid) === process.pid); + // if (checkFileExists(pidFilePath)) { + // const pid = fs.readFileSync(pidFilePath, 'utf-8'); + // if (Number(pid) === process.pid) { + // fs.unlinkSync(pidFilePath); + // console.log('server id', process.pid, 'is exit'); + // } + // } + if (findPid) { + console.log('server id', process.pid, 'is exit'); + try { + fs.unlinkSync(findPid.file); + } catch (e) { + console.log('unlinkSync error', findPid); } } process.exit(0); // 退出进程 diff --git a/src/command/config.ts b/src/command/config.ts index 6045415..da667ae 100644 --- a/src/command/config.ts +++ b/src/command/config.ts @@ -1,24 +1,51 @@ import { program as app, Command } from '@/program.ts'; -import { getConfig, writeConfig } from '@/module/index.ts'; +import { checkFileExists, getConfig, writeConfig } from '@/module/index.ts'; +import path from 'path'; +import fs from 'fs'; const command = new Command('config') .description('') .option('-d, --dev ', 'Specify dev') .option('-l --list', 'list config') + .option('-w --workdir ', 'web config') .action(async (options) => { - const { dev, list } = options || {}; + const { dev, list, workdir } = options || {}; + let config = getConfig(); + let flag = false; if (dev === 'true' || dev === 'false') { + flag = true; const config = getConfig(); if (dev === 'true') { - writeConfig({ ...config, dev: true }); + config.dev = true; } else { - writeConfig({ ...config, dev: false }); + config.dev = false; } } + if (options.workdir) { + let finalPath: string; + flag = true; + const workdir = options.workdir; + + if (workdir.startsWith('/')) { + // 如果以 / 开头,处理为绝对路径 + finalPath = workdir; + } else { + // 否则,处理为相对路径 + finalPath = path.resolve(workdir); + } + if (!checkFileExists(finalPath)) { + console.log('路径不存在'); + fs.mkdirSync(finalPath, { recursive: true }); + } + config.workdir = finalPath; + } if (list) { const config = getConfig(); console.log('config', config); } + if (flag) { + writeConfig(config); + } }); app.addCommand(command); diff --git a/src/command/login.ts b/src/command/login.ts index 885f2ed..e1841b2 100644 --- a/src/command/login.ts +++ b/src/command/login.ts @@ -53,7 +53,7 @@ const loginCommand = new Command('login') } else { console.log('登录失败', res.message || ''); } - console.log('u', username, password); + console.log('welcome', username); }); app.addCommand(loginCommand); diff --git a/src/command/router.ts b/src/command/router.ts new file mode 100644 index 0000000..e758eba --- /dev/null +++ b/src/command/router.ts @@ -0,0 +1,52 @@ +import { program as app, Command } from '@/program.ts'; +import { getConfig, writeConfig, checkFileExists } from '@/module/index.ts'; +import { createApp } from '@/app.ts'; +import fs from 'fs'; +import inquirer from 'inquirer'; +import { query } from '../module/index.ts'; +import chalk from 'chalk'; +import util from 'util'; + +// web 开发模块 +const command = new Command('router') + .description('router get') + .option('-p, --path ', '退出进程') + .option('-k, --key ', '启动进程') + .action(async (options) => { + let { path, key } = options; + // 如果没有传递参数,则通过交互式输入 + if (!path || !key) { + const answers = await inquirer.prompt([ + { + type: 'input', + name: 'path', + message: 'Enter your path:', + when: () => !path, // 当 username 为空时,提示用户输入 + }, + { + type: 'input', + name: 'key', + message: 'Enter your key:', + when: () => !key, // 当 password 为空时,提示用户输入 + }, + ]); + path = answers.path || path; + key = answers.key || key; + } + + const res = await query.post({ path, key }); + if (res?.code === 200) { + const data = res.data.map((item: any) => { + // return `id: ${item.id}, title: ${item.title}`; + + return { + id: item.id, + title: item.title, + }; + }); + console.log(chalk.green(util.inspect(data, { colors: true, depth: 4 }))); + } else { + console.log('error', res.message || ''); + } + }); +app.addCommand(command); diff --git a/src/command/web.ts b/src/command/web.ts new file mode 100644 index 0000000..3dacb9d --- /dev/null +++ b/src/command/web.ts @@ -0,0 +1,71 @@ +import { program as app, Command } from '@/program.ts'; +import { getConfig, writeConfig, checkFileExists, query } from '@/module/index.ts'; +import fs from 'fs'; +import path from 'path'; +import { startContainerServer } from '@/module/run-vite.ts'; +// web 开发模块 +const command = new Command('web') + .description('web dev manager') + .option('-e, --exit', '退出进程') + .option('-s, --start', '启动进程') + + .action(async (options) => { + const { exit, start } = options || {}; + }); +app.addCommand(command); + +// container 开发模块 +const container = new Command('container') + .description('container manager') + .option('-d, --container ', '下载镜像') + .option('-f, --force', '下载镜像') + .option('-u, --upload ', '上传镜像') + .action(async (options) => { + const { container, upload, force } = options || {}; + const config = getConfig(); + const workdir = config.workdir; + if (!workdir) { + console.log('请先配置工作目录'); + return; + } + if (!config.token) { + console.log('请先登录'); + return; + } + // 32210aa6-3d5a-4687-b769-ae4e8137ec1e + if (container) { + console.log('下载镜像', container); + const res = await query.post({ path: 'container', key: 'get', id: container }); + if (res.code !== 200) { + console.log('error', res.message || ''); + return; + } + await startContainerServer(res.data, force); + } + if (upload) { + console.log('上传镜像', upload); + const directory = path.join(workdir, 'container', upload); + if (!checkFileExists(directory)) { + console.log('文件夹不存在'); + return; + } + const code = fs.readFileSync(path.join(directory, 'index.js'), 'utf-8'); + if (!code) { + console.log('文件不能为空'); + return; + } + const res = await query.post({ + path: 'container', // + key: 'update', + data: { id: upload, code }, + }); + if (res.code !== 200) { + console.log('error', res.message || ''); + console.log(res); + return; + } + console.log('上传成功'); + } + }); + +app.addCommand(container); diff --git a/src/index.ts b/src/index.ts index 1319d95..189ae71 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,5 +6,7 @@ import './command/me.ts'; import './command/deploy.ts'; import './command/serve.ts'; import './command/config.ts'; +import './command/web.ts'; +import './command/router.ts'; program.parse(process.argv); diff --git a/src/module/get-config.ts b/src/module/get-config.ts index 0011b7c..c59dd6c 100644 --- a/src/module/get-config.ts +++ b/src/module/get-config.ts @@ -2,12 +2,23 @@ import os from 'os'; import path from 'path'; import fs from 'fs'; -const envisionPath = path.join(os.homedir(), '.config', 'envision'); +export const envisionPath = path.join(os.homedir(), '.config', 'envision'); const configPath = path.join(os.homedir(), '.config', 'envision', 'config.json'); export const pidFilePath = path.join(envisionPath, 'app.pid'); export const dbPath = path.join(envisionPath, 'db.sqlite'); - +const envisionPidDir = path.join(envisionPath); +export const getPidList = () => { + const files = fs.readdirSync(envisionPidDir); + const pidFiles = files.filter((file) => file.endsWith('.pid')); + return pidFiles.map((file) => { + const pid = fs.readFileSync(path.join(envisionPidDir, file), 'utf-8'); + return { pid, file: path.join(envisionPidDir, file) }; + }); +}; +export const writeVitePid = (pid: number) => { + fs.writeFileSync(path.join(envisionPath, `vite-${pid}.pid`), pid.toString()); +}; export const checkFileExists = (filePath: string) => { try { fs.accessSync(filePath, fs.constants.F_OK); diff --git a/src/module/run-vite.ts b/src/module/run-vite.ts new file mode 100644 index 0000000..39b46f7 --- /dev/null +++ b/src/module/run-vite.ts @@ -0,0 +1,79 @@ +import fs from 'fs'; +import path from 'path'; +import { createServer } from 'vite'; +import { checkFileExists, getConfig, writeVitePid } from './index.ts'; + +export const runVite = async (entry: string) => { + const entryDir = path.dirname(entry); + const server = await createServer({ + // Vite 配置选项 + root: entryDir, + server: { + port: 7101, // 可以根据需要设置端口 + host: '0.0.0.0', + }, + }); + await server.listen(); + console.log('Vite server is running at:', server.config.server.port); +}; +const template = ` + + + + + + Container Develop + + + + +
+ + + +`; +export const startContainerServer = async (container: any, force: boolean) => { + const { id, code } = container; + const config = getConfig(); + const workdir = config.workdir; + if (!workdir) { + console.log('请先配置工作目录'); + return; + } + if (!config.token) { + console.log('请先登录'); + return; + } + const directory = path.join(workdir, 'container', id); + if (!checkFileExists(directory) || force) { + fs.mkdirSync(directory, { recursive: true }); + fs.writeFileSync(path.join(directory, 'index.js'), code); + fs.writeFileSync(path.join(directory, 'index.html'), template); + } else { + console.log('文件夹已存在'); + } + await runVite(path.join(directory, 'index.html')); + console.log('container server is running at:', 'http://localhost:7101'); + console.log('pid:', process.pid); + writeVitePid(process.pid); +};