lvyjs 0.3.0-alpha.0 → 0.3.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/index.js CHANGED
@@ -3,6 +3,7 @@
3
3
  import { fork } from 'child_process'
4
4
  import { join, dirname, relative } from 'path'
5
5
  import { fileURLToPath } from 'node:url'
6
+ import chokidar from 'chokidar'
6
7
  const args = [...process.argv.slice(2)]
7
8
  const currentFilePath = fileURLToPath(import.meta.url)
8
9
  const currentDirPath = dirname(currentFilePath)
@@ -23,6 +24,58 @@ const dev = () => {
23
24
 
24
25
  let devProcess = null
25
26
  let pendingRestart = false // 标记是否有重启 pending
27
+ let killTimeout = null // SIGKILL 超时定时器
28
+ let restartDebounceTimer = null // 重启防抖定时器
29
+ let latestConfig = null // 最新待应用的配置
30
+ let fileWatcher = null // chokidar watcher 实例
31
+ let watchDebounce = null // watch 防抖定时器
32
+
33
+ // 解析 watch 配置
34
+ const parseWatchConfig = data => {
35
+ const w = data?.watch
36
+ if (!w) return { paths: [], delay: 500 }
37
+ if (Array.isArray(w)) return { paths: w, delay: 500 }
38
+ if (typeof w === 'object' && w.paths) {
39
+ return { paths: w.paths, delay: w.delay || 500 }
40
+ }
41
+ return { paths: [], delay: 500 }
42
+ }
43
+
44
+ // 关闭 watcher
45
+ const closeFileWatcher = async () => {
46
+ if (watchDebounce) {
47
+ clearTimeout(watchDebounce)
48
+ watchDebounce = null
49
+ }
50
+ if (fileWatcher) {
51
+ await fileWatcher.close()
52
+ fileWatcher = null
53
+ }
54
+ }
55
+
56
+ // 启动 watch 监听(支持 glob 模式,如 'src/**/*.{ts,tsx}')
57
+ const startFileWatcher = data => {
58
+ closeFileWatcher()
59
+ const { paths, delay } = parseWatchConfig(data)
60
+ if (paths.length === 0) return
61
+
62
+ fileWatcher = chokidar.watch(paths, {
63
+ cwd: process.cwd(),
64
+ ignoreInitial: true,
65
+ ignored: /(^|[\/\\])\../ // 忽略点文件
66
+ })
67
+
68
+ fileWatcher.on('all', (_event, filePath) => {
69
+ if (watchDebounce) clearTimeout(watchDebounce)
70
+ watchDebounce = setTimeout(() => {
71
+ watchDebounce = null
72
+ console.info(`[lvyjs] 监听到文件变化: ${filePath},正在重启...`)
73
+ doRestart(latestConfig || data)
74
+ }, delay)
75
+ })
76
+
77
+ fileWatcher.on('ready', () => {})
78
+ }
26
79
 
27
80
  // 启动开发进程
28
81
  const startDevProcess = data => {
@@ -31,6 +84,12 @@ const dev = () => {
31
84
  const envConfig = data?.env || {}
32
85
  // 前面1个被占用,剩余参数
33
86
  const restArgs = args.slice(1)
87
+
88
+ // 如果支持,得到 watch 配置,启动watch。
89
+ // 当watch的配置发生变化时,重启开发进程
90
+ // 复用当前的重启逻辑。
91
+ startFileWatcher(data)
92
+
34
93
  devProcess = fork(indexFileDir, restArgs, {
35
94
  stdio: 'inherit',
36
95
  execArgv: [
@@ -67,11 +126,31 @@ const dev = () => {
67
126
  })
68
127
  }
69
128
 
70
- // 优雅重启开发进程
129
+ // 优雅重启开发进程(带防抖,避免密集重启)
71
130
  const restartDevProcess = newConfig => {
131
+ // 保存最新配置,防抖后使用
132
+ latestConfig = newConfig
133
+
134
+ if (restartDebounceTimer) clearTimeout(restartDebounceTimer)
135
+ restartDebounceTimer = setTimeout(() => {
136
+ restartDebounceTimer = null
137
+ doRestart(latestConfig)
138
+ }, 500)
139
+ }
140
+
141
+ const doRestart = config => {
142
+ // 关闭旧的文件监听
143
+ closeFileWatcher()
144
+
72
145
  if (!devProcess) {
73
146
  // 没有运行中的进程,直接启动
74
- startDevProcess(newConfig)
147
+ startDevProcess(config)
148
+ return
149
+ }
150
+
151
+ // 如果已经在等待重启,只更新配置,不重复 kill
152
+ if (pendingRestart) {
153
+ latestConfig = config
75
154
  return
76
155
  }
77
156
 
@@ -80,15 +159,22 @@ const dev = () => {
80
159
 
81
160
  // 监听退出事件,确保旧进程完全结束后再启动新进程
82
161
  devProcess.once('exit', () => {
162
+ // 清除 SIGKILL 超时定时器
163
+ if (killTimeout) {
164
+ clearTimeout(killTimeout)
165
+ killTimeout = null
166
+ }
83
167
  pendingRestart = false
84
- startDevProcess(newConfig)
168
+ // 使用最新的配置启动
169
+ startDevProcess(latestConfig || config)
85
170
  })
86
171
 
87
172
  // 发送终止信号
88
173
  devProcess.kill('SIGTERM')
89
174
 
90
175
  // 超时保护:如果 5 秒后还没退出,强制杀掉
91
- setTimeout(() => {
176
+ killTimeout = setTimeout(() => {
177
+ killTimeout = null
92
178
  if (devProcess && !devProcess.killed) {
93
179
  console.info('[lvyjs] 开发进程无响应,强制终止')
94
180
  devProcess.kill('SIGKILL')
@@ -131,6 +217,7 @@ const dev = () => {
131
217
  // 处理主进程退出
132
218
  process.on('SIGINT', () => {
133
219
  console.log('\n[lvyjs] 正在退出...')
220
+ closeFileWatcher()
134
221
  if (devProcess) devProcess.kill()
135
222
  if (readConfigFork) readConfigFork.kill()
136
223
  process.exit(0)
@@ -1,4 +1,7 @@
1
- .warning, .error, .success, .message {
1
+ .warning,
2
+ .error,
3
+ .success,
4
+ .message {
2
5
  border: 1px solid #ccc;
3
6
  padding: 10px;
4
7
  color: #333;
@@ -17,13 +20,13 @@
17
20
  }
18
21
 
19
22
  .info {
20
- background: #A9A9A9;
23
+ background: #a9a9a9;
21
24
  box-shadow: 0 0 1px rgba(169, 169, 169, 0.25);
22
25
  color: #fff;
23
26
  }
24
27
 
25
28
  .alert {
26
- background: #8B0000;
29
+ background: #8b0000;
27
30
  box-shadow: 0 0 1px rgba(139, 0, 0, 0.25);
28
31
  color: #fff;
29
32
  }
@@ -32,4 +35,4 @@
32
35
  background: #006400;
33
36
  box-shadow: 0 0 1px rgba(0, 100, 0, 0.25);
34
37
  color: #fff;
35
- }
38
+ }
@@ -24,7 +24,10 @@ body {
24
24
  border-color: yellow;
25
25
  }
26
26
 
27
- .warning, .error, .success, .message {
27
+ .warning,
28
+ .error,
29
+ .success,
30
+ .message {
28
31
  border: 1px solid #ccc;
29
32
  padding: 10px;
30
33
  color: #333;
@@ -52,4 +55,4 @@ body {
52
55
  background: #8b0000;
53
56
  box-shadow: 0 0 1px rgba(139, 0, 0, 0.25);
54
57
  color: #fff;
55
- }
58
+ }
package/lib/readConfig.js CHANGED
@@ -56,11 +56,17 @@ const main = async () => {
56
56
  };
57
57
  // 首次发送
58
58
  await sendConfig();
59
- // 监听文件变化
59
+ // 监听文件变化(带防抖,避免多次触发)
60
+ let debounceTimer = null;
60
61
  watch(process.cwd(), (_event, filename) => {
61
62
  if (files.includes(filename)) {
62
- console.info(`[lvyjs] 配置文件 ${filename} 已变化,重新加载...`);
63
- sendConfig();
63
+ if (debounceTimer)
64
+ clearTimeout(debounceTimer);
65
+ debounceTimer = setTimeout(() => {
66
+ debounceTimer = null;
67
+ console.info(`[lvyjs] 配置文件 ${filename} 已变化,重新加载...`);
68
+ sendConfig();
69
+ }, 300);
64
70
  }
65
71
  });
66
72
  // 保持进程运行
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lvyjs",
3
- "version": "0.3.0-alpha.0",
3
+ "version": "0.3.0-alpha.1",
4
4
  "description": "tsx compile script",
5
5
  "author": "lemonade",
6
6
  "license": "MIT",