napcat-plugin-debug-cli 1.2.2 → 1.2.4

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.
Files changed (3) hide show
  1. package/cli.mjs +31 -2
  2. package/package.json +1 -1
  3. package/vite.mjs +144 -1
package/cli.mjs CHANGED
@@ -5149,13 +5149,42 @@ function createWatcher(watchPath, onPluginChange) {
5149
5149
  const watchers = /* @__PURE__ */ new Map();
5150
5150
  const timers = /* @__PURE__ */ new Map();
5151
5151
  let active = false;
5152
- const EXTS = /* @__PURE__ */ new Set([".js", ".mjs", ".cjs", ".ts", ".mts", ".json"]);
5152
+ const EXTS = /* @__PURE__ */ new Set([
5153
+ ".js",
5154
+ ".mjs",
5155
+ ".cjs",
5156
+ ".ts",
5157
+ ".mts",
5158
+ ".cts",
5159
+ ".json",
5160
+ // 前端 / WebUI 相关
5161
+ ".jsx",
5162
+ ".tsx",
5163
+ ".vue",
5164
+ ".svelte",
5165
+ ".html",
5166
+ ".htm",
5167
+ ".css",
5168
+ ".scss",
5169
+ ".sass",
5170
+ ".less",
5171
+ ".styl",
5172
+ ".svg",
5173
+ ".png",
5174
+ ".jpg",
5175
+ ".jpeg",
5176
+ ".gif",
5177
+ ".webp",
5178
+ ".ico"
5179
+ ]);
5180
+ const IGNORE_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".vite", ".cache"]);
5153
5181
  function watchDir(name, dirPath) {
5154
5182
  try {
5155
5183
  const w = fs.watch(dirPath, { recursive: true, persistent: false }, (_ev, file) => {
5156
5184
  if (!file) return;
5157
5185
  if (!EXTS.has(path.extname(file))) return;
5158
- if (file.includes("node_modules") || file.startsWith(".")) return;
5186
+ const parts = file.split(/[\\/]/);
5187
+ if (parts.some((p) => IGNORE_DIRS.has(p) || p.startsWith("."))) return;
5159
5188
  const t = timers.get(name);
5160
5189
  if (t) clearTimeout(t);
5161
5190
  timers.set(name, setTimeout(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "napcat-plugin-debug-cli",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "type": "module",
5
5
  "description": "NapCat 插件调试 CLI — 连接调试服务实现热重载",
6
6
  "author": "NapNeko",
package/vite.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
+ import { execSync } from 'node:child_process';
3
4
 
4
5
  const C = {
5
6
  reset: "\x1B[0m",
@@ -86,13 +87,17 @@ function napcatHmrPlugin(options = {}) {
86
87
  wsUrl = "ws://127.0.0.1:8998",
87
88
  token,
88
89
  enabled = true,
89
- autoConnect = true
90
+ autoConnect = true,
91
+ webui
90
92
  } = options;
93
+ const webuiConfigs = webui ? Array.isArray(webui) ? webui : [webui] : [];
91
94
  let rpc = null;
92
95
  let remotePluginPath = null;
93
96
  let connecting = false;
94
97
  let config;
95
98
  let isFirstBuild = true;
99
+ const webuiWatchers = [];
100
+ let webuiDeployDebounceTimer = null;
96
101
  async function connect() {
97
102
  if (rpc?.connected) return true;
98
103
  if (connecting) return false;
@@ -183,6 +188,37 @@ function napcatHmrPlugin(options = {}) {
183
188
  logErr(`复制文件失败: ${e.message}`);
184
189
  return;
185
190
  }
191
+ const projectRoot = config.root || process.cwd();
192
+ for (const wc of webuiConfigs) {
193
+ const webuiTargetDir = wc.targetDir || "webui";
194
+ const webuiDistDir = path.resolve(projectRoot, wc.distDir);
195
+ const webuiRoot = wc.root ? path.resolve(projectRoot, wc.root) : path.dirname(webuiDistDir);
196
+ if (wc.buildCommand) {
197
+ try {
198
+ log(`构建 WebUI (${co(webuiTargetDir, C.cyan)})...`);
199
+ execSync(wc.buildCommand, {
200
+ cwd: webuiRoot,
201
+ stdio: "pipe",
202
+ env: { ...process.env, NODE_ENV: "production" }
203
+ });
204
+ logOk(`WebUI (${webuiTargetDir}) 构建完成`);
205
+ } catch (e) {
206
+ logErr(`WebUI (${webuiTargetDir}) 构建失败: ${e.stderr?.toString() || e.message}`);
207
+ continue;
208
+ }
209
+ }
210
+ if (!fs.existsSync(webuiDistDir)) {
211
+ logErr(`WebUI 产物目录不存在: ${webuiDistDir}`);
212
+ continue;
213
+ }
214
+ try {
215
+ const webuiDestDir = path.join(destDir, webuiTargetDir);
216
+ copyDirRecursive(webuiDistDir, webuiDestDir);
217
+ logOk(`WebUI (${webuiTargetDir}) 已部署 (${countFiles(webuiDistDir)} 个文件)`);
218
+ } catch (e) {
219
+ logErr(`WebUI (${webuiTargetDir}) 部署失败: ${e.message}`);
220
+ }
221
+ }
186
222
  try {
187
223
  const reloaded = await rpc.call("reloadPlugin", pluginName);
188
224
  if (reloaded === false) {
@@ -203,6 +239,98 @@ function napcatHmrPlugin(options = {}) {
203
239
  }
204
240
  }
205
241
  }
242
+ async function deployWebuiOnly() {
243
+ if (!rpc?.connected || !remotePluginPath) {
244
+ logErr("未连接到调试服务,跳过 WebUI 部署");
245
+ return;
246
+ }
247
+ const distDir = path.resolve(config.build.outDir);
248
+ const pkgPath = path.join(distDir, "package.json");
249
+ if (!fs.existsSync(pkgPath)) {
250
+ logErr("dist/package.json 不存在,跳过 WebUI 部署");
251
+ return;
252
+ }
253
+ let pluginName;
254
+ try {
255
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
256
+ pluginName = pkg.name;
257
+ if (!pluginName) return;
258
+ } catch {
259
+ return;
260
+ }
261
+ const destDir = path.join(remotePluginPath, pluginName);
262
+ const projectRoot = config.root || process.cwd();
263
+ let hasChanges = false;
264
+ for (const wc of webuiConfigs) {
265
+ const webuiTargetDir = wc.targetDir || "webui";
266
+ const webuiDistDir = path.resolve(projectRoot, wc.distDir);
267
+ const webuiRoot = wc.root ? path.resolve(projectRoot, wc.root) : path.dirname(webuiDistDir);
268
+ if (wc.buildCommand) {
269
+ try {
270
+ log(`构建 WebUI (${co(webuiTargetDir, C.cyan)})...`);
271
+ execSync(wc.buildCommand, {
272
+ cwd: webuiRoot,
273
+ stdio: "pipe",
274
+ env: { ...process.env, NODE_ENV: "production" }
275
+ });
276
+ logOk(`WebUI (${webuiTargetDir}) 构建完成`);
277
+ } catch (e) {
278
+ logErr(`WebUI (${webuiTargetDir}) 构建失败: ${e.stderr?.toString() || e.message}`);
279
+ continue;
280
+ }
281
+ }
282
+ if (!fs.existsSync(webuiDistDir)) {
283
+ logErr(`WebUI 产物目录不存在: ${webuiDistDir}`);
284
+ continue;
285
+ }
286
+ try {
287
+ const webuiDestDir = path.join(destDir, webuiTargetDir);
288
+ if (fs.existsSync(webuiDestDir)) {
289
+ fs.rmSync(webuiDestDir, { recursive: true, force: true });
290
+ }
291
+ copyDirRecursive(webuiDistDir, webuiDestDir);
292
+ logOk(`WebUI (${webuiTargetDir}) 已部署 (${countFiles(webuiDistDir)} 个文件)`);
293
+ hasChanges = true;
294
+ } catch (e) {
295
+ logErr(`WebUI (${webuiTargetDir}) 部署失败: ${e.message}`);
296
+ }
297
+ }
298
+ if (hasChanges) {
299
+ try {
300
+ await rpc.call("reloadPlugin", pluginName);
301
+ logHmr(`${co(pluginName, C.green, C.bold)} 已重载 (WebUI 更新)`);
302
+ } catch (e) {
303
+ logErr(`重载失败: ${e.message}`);
304
+ }
305
+ }
306
+ }
307
+ function startWebuiWatchers(projectRoot) {
308
+ for (const wc of webuiConfigs) {
309
+ if (!wc.watchDir) continue;
310
+ const watchPath = path.resolve(projectRoot, wc.watchDir);
311
+ const webuiTargetDir = wc.targetDir || "webui";
312
+ if (!fs.existsSync(watchPath)) {
313
+ logErr(`WebUI watchDir 不存在: ${watchPath}`);
314
+ continue;
315
+ }
316
+ try {
317
+ const watcher = fs.watch(watchPath, { recursive: true }, (_event, filename) => {
318
+ if (!filename) return;
319
+ const normalized = filename.replace(/\\/g, "/");
320
+ if (normalized.includes("node_modules") || normalized.includes("/dist/") || normalized.startsWith("dist/") || normalized.startsWith(".")) return;
321
+ if (webuiDeployDebounceTimer) clearTimeout(webuiDeployDebounceTimer);
322
+ webuiDeployDebounceTimer = setTimeout(() => {
323
+ log(`WebUI 文件变化: ${co(normalized, C.dim)}`);
324
+ deployWebuiOnly().catch((e) => logErr(`WebUI 部署出错: ${e.message}`));
325
+ }, 300);
326
+ });
327
+ webuiWatchers.push(watcher);
328
+ logOk(`监听 WebUI (${webuiTargetDir}): ${co(watchPath, C.dim)}`);
329
+ } catch (e) {
330
+ logErr(`无法监听 WebUI 目录: ${e.message}`);
331
+ }
332
+ }
333
+ }
206
334
  return {
207
335
  name: "napcat-hmr",
208
336
  apply: "build",
@@ -230,9 +358,24 @@ function napcatHmrPlugin(options = {}) {
230
358
  if (!ok) return;
231
359
  }
232
360
  await deployAndReload(distDir);
361
+ if (isFirstBuild && config.build.watch && webuiConfigs.some((wc) => wc.watchDir)) {
362
+ const projectRoot = config.root || process.cwd();
363
+ startWebuiWatchers(projectRoot);
364
+ }
233
365
  isFirstBuild = false;
234
366
  },
235
367
  closeBundle() {
368
+ for (const w of webuiWatchers) {
369
+ try {
370
+ w.close();
371
+ } catch {
372
+ }
373
+ }
374
+ webuiWatchers.length = 0;
375
+ if (webuiDeployDebounceTimer) {
376
+ clearTimeout(webuiDeployDebounceTimer);
377
+ webuiDeployDebounceTimer = null;
378
+ }
236
379
  if (config.build.watch) return;
237
380
  rpc?.close();
238
381
  rpc = null;