技术参数
- 前端:Vanilla JS + TypeScript + Vite
- 后端:Node.js + TypeScript + Nodemon
- 前后端都使用
.mts后缀
项目结构
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
希望实现的目标
- 后端修改
.mts文件后,自动编译为.mjs,然后自动重启后端,已知ts-node运行.mts文件有一堆报错 tsc -w和nodemon和vite每一个都会阻塞终端,但我希望能实现npm run dev一步到位启动前后端开发环境
我目前的方案(期待大大佬给给建议)
-
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))