项目结构
client/ --- 前端 Vite 项目
src/main.mts --- 前端 TS 代码文件
index.html --- Vite 入口
vite.config.mts --- Vite 配置
tsconfig.json --- 前端 TS 配置
package.json
server/ --- 后端 Node.js Koa 项目
src/main.mts --- 后端 TS 代码文件
tsconfig.json --- 后端 TS 配置
package.json
dev.mjs
package.json
希望实现的目标
我目前的方案(期待大大佬给给建议)
client/package.json{
"build": "vite build",
"dev": "vite --host=0.0.0.0",
"preview": "vite preview"
}
server/package.json{
"build": "tsc",
"build:watch": "tsc -w",
"dev": "nodemon dist/main.mjs"
}
package.json{
"build:client": "npm run build --prefix client",
"build:server": "npm run build --prefix server",
"build": "npm run build:client && npm run build:server",
"dev:client": "npm run dev --prefix client",
"dev:server": "npm run dev --prefix server",
"build:watch:server": "npm run build:watch --prefix server",
"dev": "node dev.mjs"
}
dev.mjs
本来想用 concurrently 并发执行 tsc -w 和 nodemon 和 vite 的,可是 nodemon 执行前必须要确保待执行的 .mjs 文件存在,可是 tsc -w 不一定来得及编译完成,所以我就在 concurrently 加一个一次性的 tsc,可是 concurrently 会执行一次 nodemon,tsc -w 又会触发一次 nodemon,如果 Koa 在服务运行中时还打印内容的话,终端就会出现重复的一堆打印内容,实在不优雅。
import { spawn } from 'cross-spawn'
const tscWatchProcess = spawn('npm', ['run', 'build:watch:server'])
await new Promise((resolve, reject) => {
tscWatchProcess.stdout.on('data',
/** @param {Buffer} chunk */
chunk => {
if (chunk.toString().includes('Watching for file changes')) {
resolve()
}
}
)
tscWatchProcess.stdout.on('error', reject)
tscWatchProcess.stderr.on('error', reject)
tscWatchProcess.stderr.on('data', reject)
})
const viteProcess = spawn('npm', ['run', 'dev:client'])
const modemonProcess = spawn('npm', ['run', 'dev:server'])
/**
* @param {string} tag
* @param {Buffer} chunk
* @param {boolean} isError
*/
const handler = (tag, chunk) => {
chunk.toString().split('\n').forEach(line => {
if (line) console.log(`${line}`)
})
}
viteProcess.stdout.on('data', chunk => handler('client', chunk))
modemonProcess.stdout.on('data', chunk => handler('server', chunk))
viteProcess.stderr.on('data', chunk => handler('client', chunk))
modemonProcess.stderr.on('data', chunk => handler('server', chunk))