@open-wxa/wxa-runner-core 0.12.1 → 0.12.3
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/dist/index.d.mts +8 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.js +118 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +118 -13
- package/dist/index.mjs.map +1 -1
- package/dist/runtime/frame.js +28 -2
- package/dist/runtime/frame.js.map +1 -1
- package/dist/runtime/host.js +34 -5
- package/dist/runtime/host.js.map +1 -1
- package/dist/{setup-D0ubZt2C.d.mts → setup--EIOgQvG.d.mts} +2 -0
- package/dist/{setup-D0ubZt2C.d.ts → setup--EIOgQvG.d.ts} +2 -0
- package/dist/setup.d.mts +1 -1
- package/dist/setup.d.ts +1 -1
- package/dist/test-api.d.mts +2 -2
- package/dist/test-api.d.ts +2 -2
- package/dist/{testApi-Df0ltBI6.d.ts → testApi-BfzCTOhg.d.ts} +1 -1
- package/dist/{testApi-x2Yph6M2.d.mts → testApi-CoYw0cPm.d.mts} +1 -1
- package/dist/web.d.mts +3 -0
- package/dist/web.d.ts +3 -0
- package/dist/web.js +20 -0
- package/dist/web.js.map +1 -1
- package/dist/web.mjs +20 -0
- package/dist/web.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import http, { IncomingMessage, ServerResponse } from 'http';
|
|
2
2
|
import { ResolvedBaseLib } from '@open-wxa/wxa-runner-extractor';
|
|
3
|
-
import { D as DeviceProfile, F as ForwardConsole } from './setup
|
|
4
|
-
export { A as ApiContext, a as ApiHandler, b as ApiResult, c as AppInfo, M as MockConfig, d as MockRequest, e as MockResponse, f as MockValue, N as NetworkConfig, R as RouteHandler, S as SetupApi, g as SetupConfig, h as SetupContext, i as SetupDefinition } from './setup
|
|
3
|
+
import { D as DeviceProfile, F as ForwardConsole } from './setup--EIOgQvG.mjs';
|
|
4
|
+
export { A as ApiContext, a as ApiHandler, b as ApiResult, c as AppInfo, M as MockConfig, d as MockRequest, e as MockResponse, f as MockValue, N as NetworkConfig, R as RouteHandler, S as SetupApi, g as SetupConfig, h as SetupContext, i as SetupDefinition } from './setup--EIOgQvG.mjs';
|
|
5
5
|
import { Request, Response } from 'express';
|
|
6
|
-
export { F as FrameError, P as PageSnapshot, R as RecordedRequest, W as WebViewInfo, a as WxaTestApi } from './testApi-
|
|
6
|
+
export { F as FrameError, P as PageSnapshot, R as RecordedRequest, W as WebViewInfo, a as WxaTestApi } from './testApi-CoYw0cPm.mjs';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* 样式预处理:project.config.json 的 setting.useCompilerPlugins 开启 less / sass 时,
|
|
@@ -266,6 +266,7 @@ interface ExtensionEntry {
|
|
|
266
266
|
* /__wxa__/usr/<会话>/<路径> 用户目录(USER_DATA_PATH)下的文件,image 等组件和 uploadFile 按地址读取
|
|
267
267
|
* /__wxa__/region/<kind> 地区选择器用的行政区划数据(districts / streets),取自本机开发者工具
|
|
268
268
|
* /__wxa__/api/* --devtools-login:wx.login 的 code、手机号,服务市场、插件的请求转发,只允许本机访问
|
|
269
|
+
* /__wxa__/socket 带自定义请求头的 WebSocket 转发,只接受同源连接
|
|
269
270
|
* /__wxa__/ws 文件变化通知:热更新(hot)或整页刷新(reload);开启 forwardConsole 时浏览器从这里发来报错
|
|
270
271
|
* middlewares / 扩展挂载的路径 排在 runner 自己的路由之前
|
|
271
272
|
* 其余路径 小程序目录下的静态资源
|
|
@@ -355,8 +356,11 @@ declare class DevServer {
|
|
|
355
356
|
private readonly logger;
|
|
356
357
|
private readonly app;
|
|
357
358
|
private server;
|
|
359
|
+
private socketProxy;
|
|
358
360
|
private sockets;
|
|
359
361
|
private watcher;
|
|
362
|
+
/** 上次编译失败时页面上显示着错误,修好后整页刷新才能清掉 */
|
|
363
|
+
private lastBuildFailed;
|
|
360
364
|
private address;
|
|
361
365
|
private lanAccess;
|
|
362
366
|
/** 运行时生成的临时文件(canvas 导出、拍照等),随服务器进程存在 */
|
|
@@ -386,6 +390,7 @@ declare class DevServer {
|
|
|
386
390
|
private runtimeDir;
|
|
387
391
|
/** 只在监听文件变化时打开基础库的热更新开关,跑测试(watch: false)时运行环境与真机一致 */
|
|
388
392
|
private get hotEnabled();
|
|
393
|
+
/** 返回初次扫描完成的时刻,此前已存在的文件不会作为改动报告 */
|
|
389
394
|
private startWatching;
|
|
390
395
|
private broadcast;
|
|
391
396
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import http, { IncomingMessage, ServerResponse } from 'http';
|
|
2
2
|
import { ResolvedBaseLib } from '@open-wxa/wxa-runner-extractor';
|
|
3
|
-
import { D as DeviceProfile, F as ForwardConsole } from './setup
|
|
4
|
-
export { A as ApiContext, a as ApiHandler, b as ApiResult, c as AppInfo, M as MockConfig, d as MockRequest, e as MockResponse, f as MockValue, N as NetworkConfig, R as RouteHandler, S as SetupApi, g as SetupConfig, h as SetupContext, i as SetupDefinition } from './setup
|
|
3
|
+
import { D as DeviceProfile, F as ForwardConsole } from './setup--EIOgQvG.js';
|
|
4
|
+
export { A as ApiContext, a as ApiHandler, b as ApiResult, c as AppInfo, M as MockConfig, d as MockRequest, e as MockResponse, f as MockValue, N as NetworkConfig, R as RouteHandler, S as SetupApi, g as SetupConfig, h as SetupContext, i as SetupDefinition } from './setup--EIOgQvG.js';
|
|
5
5
|
import { Request, Response } from 'express';
|
|
6
|
-
export { F as FrameError, P as PageSnapshot, R as RecordedRequest, W as WebViewInfo, a as WxaTestApi } from './testApi-
|
|
6
|
+
export { F as FrameError, P as PageSnapshot, R as RecordedRequest, W as WebViewInfo, a as WxaTestApi } from './testApi-BfzCTOhg.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* 样式预处理:project.config.json 的 setting.useCompilerPlugins 开启 less / sass 时,
|
|
@@ -266,6 +266,7 @@ interface ExtensionEntry {
|
|
|
266
266
|
* /__wxa__/usr/<会话>/<路径> 用户目录(USER_DATA_PATH)下的文件,image 等组件和 uploadFile 按地址读取
|
|
267
267
|
* /__wxa__/region/<kind> 地区选择器用的行政区划数据(districts / streets),取自本机开发者工具
|
|
268
268
|
* /__wxa__/api/* --devtools-login:wx.login 的 code、手机号,服务市场、插件的请求转发,只允许本机访问
|
|
269
|
+
* /__wxa__/socket 带自定义请求头的 WebSocket 转发,只接受同源连接
|
|
269
270
|
* /__wxa__/ws 文件变化通知:热更新(hot)或整页刷新(reload);开启 forwardConsole 时浏览器从这里发来报错
|
|
270
271
|
* middlewares / 扩展挂载的路径 排在 runner 自己的路由之前
|
|
271
272
|
* 其余路径 小程序目录下的静态资源
|
|
@@ -355,8 +356,11 @@ declare class DevServer {
|
|
|
355
356
|
private readonly logger;
|
|
356
357
|
private readonly app;
|
|
357
358
|
private server;
|
|
359
|
+
private socketProxy;
|
|
358
360
|
private sockets;
|
|
359
361
|
private watcher;
|
|
362
|
+
/** 上次编译失败时页面上显示着错误,修好后整页刷新才能清掉 */
|
|
363
|
+
private lastBuildFailed;
|
|
360
364
|
private address;
|
|
361
365
|
private lanAccess;
|
|
362
366
|
/** 运行时生成的临时文件(canvas 导出、拍照等),随服务器进程存在 */
|
|
@@ -386,6 +390,7 @@ declare class DevServer {
|
|
|
386
390
|
private runtimeDir;
|
|
387
391
|
/** 只在监听文件变化时打开基础库的热更新开关,跑测试(watch: false)时运行环境与真机一致 */
|
|
388
392
|
private get hotEnabled();
|
|
393
|
+
/** 返回初次扫描完成的时刻,此前已存在的文件不会作为改动报告 */
|
|
389
394
|
private startWatching;
|
|
390
395
|
private broadcast;
|
|
391
396
|
}
|
package/dist/index.js
CHANGED
|
@@ -140,6 +140,26 @@ var FileStore = class {
|
|
|
140
140
|
this.write(destPath, this.read(srcPath));
|
|
141
141
|
return {};
|
|
142
142
|
},
|
|
143
|
+
rename: ({ oldPath, newPath }) => {
|
|
144
|
+
const source = this.normalize(oldPath);
|
|
145
|
+
const target = this.normalize(newPath);
|
|
146
|
+
const node = this.existing(oldPath);
|
|
147
|
+
this.assertNotRoot(source);
|
|
148
|
+
this.assertNotRoot(target);
|
|
149
|
+
if (source === target) return {};
|
|
150
|
+
const parent = target.slice(0, target.lastIndexOf("/")) || "/";
|
|
151
|
+
if (!this.nodes.get(parent)?.dir) throw new Error(`no such file or directory ${newPath}`);
|
|
152
|
+
if (node.dir && target.startsWith(source + "/")) throw new Error("invalid argument: directory moved into itself");
|
|
153
|
+
const destination = this.nodes.get(target);
|
|
154
|
+
if (destination) {
|
|
155
|
+
if (destination.dir !== node.dir) throw new Error(`incompatible file type ${newPath}`);
|
|
156
|
+
if (destination.dir && this.readdir(target).length) throw new Error(`directory not empty ${newPath}`);
|
|
157
|
+
}
|
|
158
|
+
const entries = [...this.nodes].filter(([key]) => key === source || node.dir && key.startsWith(source + "/"));
|
|
159
|
+
for (const [key] of entries) this.nodes.delete(key);
|
|
160
|
+
for (const [key, value] of entries) this.nodes.set(target + key.slice(source.length), value);
|
|
161
|
+
return {};
|
|
162
|
+
},
|
|
143
163
|
access: ({ path: path7 }) => {
|
|
144
164
|
this.existing(path7);
|
|
145
165
|
return {};
|
|
@@ -267,7 +287,7 @@ var import_net = __toESM(require("net"));
|
|
|
267
287
|
var import_os3 = __toESM(require("os"));
|
|
268
288
|
var import_path6 = __toESM(require("path"));
|
|
269
289
|
var import_express2 = __toESM(require("express"));
|
|
270
|
-
var
|
|
290
|
+
var import_ws3 = require("ws");
|
|
271
291
|
var import_wxa_runner_extractor5 = require("@open-wxa/wxa-runner-extractor");
|
|
272
292
|
|
|
273
293
|
// src/project/AppBuilder.ts
|
|
@@ -622,8 +642,8 @@ var AppBuilder = class {
|
|
|
622
642
|
this.pending = { covers: this.changes, result: result2 };
|
|
623
643
|
}
|
|
624
644
|
const { covers, result } = this.pending;
|
|
625
|
-
|
|
626
|
-
|
|
645
|
+
if (covers >= wanted) return result;
|
|
646
|
+
await result.catch(() => void 0);
|
|
627
647
|
}
|
|
628
648
|
}
|
|
629
649
|
/**
|
|
@@ -1453,6 +1473,71 @@ async function handleProxy(req, res) {
|
|
|
1453
1473
|
}
|
|
1454
1474
|
}
|
|
1455
1475
|
|
|
1476
|
+
// src/server/socketProxy.ts
|
|
1477
|
+
var import_ws = require("ws");
|
|
1478
|
+
function mirrorClose(to, code, reason) {
|
|
1479
|
+
if (code === 1005) to.close();
|
|
1480
|
+
else if (code === 1006 || code === 1015) to.terminate();
|
|
1481
|
+
else to.close(code, reason);
|
|
1482
|
+
}
|
|
1483
|
+
function createSocketProxy() {
|
|
1484
|
+
const server = new import_ws.WebSocketServer({
|
|
1485
|
+
noServer: true,
|
|
1486
|
+
// 不能让其他网站借本地开发服务器建立任意带凭据的连接。
|
|
1487
|
+
verifyClient: ({ origin, req }) => origin === `http://${req.headers.host}`
|
|
1488
|
+
});
|
|
1489
|
+
server.on("connection", (client) => {
|
|
1490
|
+
let upstream;
|
|
1491
|
+
const timer = setTimeout(() => client.close(1008, "Missing socket request"), 1e4);
|
|
1492
|
+
timer.unref();
|
|
1493
|
+
client.on("error", () => void 0);
|
|
1494
|
+
client.once("message", (data, binary) => {
|
|
1495
|
+
clearTimeout(timer);
|
|
1496
|
+
try {
|
|
1497
|
+
if (binary || data.toString().length > 64 * 1024) throw new Error("Invalid socket request");
|
|
1498
|
+
const { url, header: header2, protocols, timeout } = JSON.parse(data.toString());
|
|
1499
|
+
const target = new URL(url);
|
|
1500
|
+
if (!["ws:", "wss:"].includes(target.protocol) || target.username || target.password) throw new Error("Invalid socket URL");
|
|
1501
|
+
upstream = new import_ws.WebSocket(target, protocols || [], {
|
|
1502
|
+
headers: header2 || {},
|
|
1503
|
+
handshakeTimeout: typeof timeout === "number" && timeout > 0 ? timeout : 6e4
|
|
1504
|
+
});
|
|
1505
|
+
} catch {
|
|
1506
|
+
client.close(1008, "Invalid socket request");
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1509
|
+
const socket = upstream;
|
|
1510
|
+
let header = {};
|
|
1511
|
+
socket.on("upgrade", (response) => {
|
|
1512
|
+
header = response.headers;
|
|
1513
|
+
});
|
|
1514
|
+
socket.on("open", () => {
|
|
1515
|
+
if (client.readyState !== import_ws.WebSocket.OPEN) {
|
|
1516
|
+
socket.close();
|
|
1517
|
+
return;
|
|
1518
|
+
}
|
|
1519
|
+
client.send(JSON.stringify({ ready: true, header }));
|
|
1520
|
+
});
|
|
1521
|
+
socket.on("message", (message, isBinary) => {
|
|
1522
|
+
if (client.readyState === import_ws.WebSocket.OPEN) client.send(message, { binary: isBinary });
|
|
1523
|
+
});
|
|
1524
|
+
client.on("message", (message, isBinary) => {
|
|
1525
|
+
if (socket.readyState === import_ws.WebSocket.OPEN) socket.send(message, { binary: isBinary });
|
|
1526
|
+
});
|
|
1527
|
+
socket.on("error", () => client.terminate());
|
|
1528
|
+
socket.on("close", (code, reason) => {
|
|
1529
|
+
if (client.readyState === import_ws.WebSocket.OPEN) mirrorClose(client, code, reason);
|
|
1530
|
+
});
|
|
1531
|
+
});
|
|
1532
|
+
client.on("close", (code, reason) => {
|
|
1533
|
+
clearTimeout(timer);
|
|
1534
|
+
if (upstream?.readyState === import_ws.WebSocket.OPEN) mirrorClose(upstream, code, reason);
|
|
1535
|
+
else if (upstream) upstream.terminate();
|
|
1536
|
+
});
|
|
1537
|
+
});
|
|
1538
|
+
return server;
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1456
1541
|
// src/server/hmr.ts
|
|
1457
1542
|
var STYLE_FILE = /\.(wxss|less|scss|sass|css)$/;
|
|
1458
1543
|
function planHotUpdate(files, units) {
|
|
@@ -1471,7 +1556,7 @@ function planHotUpdate(files, units) {
|
|
|
1471
1556
|
var import_child_process = require("child_process");
|
|
1472
1557
|
var import_crypto = require("crypto");
|
|
1473
1558
|
var import_promises2 = require("timers/promises");
|
|
1474
|
-
var
|
|
1559
|
+
var import_ws2 = require("ws");
|
|
1475
1560
|
var import_wxa_runner_extractor = require("@open-wxa/wxa-runner-extractor");
|
|
1476
1561
|
var AUTO_PORT = 9420;
|
|
1477
1562
|
var CLI_TIMEOUT = 6e4;
|
|
@@ -1562,7 +1647,7 @@ function cliErrorMessage(stdout) {
|
|
|
1562
1647
|
function requestTicket(port) {
|
|
1563
1648
|
return new Promise((resolve, reject) => {
|
|
1564
1649
|
const id = `wxa-runner-${(0, import_crypto.randomUUID)()}`;
|
|
1565
|
-
const socket = new
|
|
1650
|
+
const socket = new import_ws2.WebSocket(`ws://127.0.0.1:${port}`);
|
|
1566
1651
|
const settle = (finish) => {
|
|
1567
1652
|
clearTimeout(timer);
|
|
1568
1653
|
socket.removeAllListeners().on("error", () => void 0).terminate();
|
|
@@ -1948,8 +2033,11 @@ var DevServer = class {
|
|
|
1948
2033
|
constructor(options) {
|
|
1949
2034
|
this.options = options;
|
|
1950
2035
|
this.server = null;
|
|
2036
|
+
this.socketProxy = null;
|
|
1951
2037
|
this.sockets = null;
|
|
1952
2038
|
this.watcher = null;
|
|
2039
|
+
/** 上次编译失败时页面上显示着错误,修好后整页刷新才能清掉 */
|
|
2040
|
+
this.lastBuildFailed = false;
|
|
1953
2041
|
this.address = "";
|
|
1954
2042
|
this.lanAccess = false;
|
|
1955
2043
|
/** 运行时生成的临时文件(canvas 导出、拍照等),随服务器进程存在 */
|
|
@@ -1993,20 +2081,27 @@ var DevServer = class {
|
|
|
1993
2081
|
return Object.values(import_os3.default.networkInterfaces()).flat().filter((net2) => net2 && net2.family === "IPv4" && !net2.internal).map((net2) => `http://${net2.address}:${port}`);
|
|
1994
2082
|
}
|
|
1995
2083
|
async start() {
|
|
2084
|
+
if (this.options.watch !== false) await this.startWatching();
|
|
1996
2085
|
try {
|
|
1997
2086
|
const build2 = await this.builder.build();
|
|
1998
2087
|
this.logger.log(`[wxa-runner] \u7F16\u8BD1\u5B8C\u6210\uFF1A${build2.pages.length} \u4E2A\u9875\u9762\uFF0C${build2.components.length} \u4E2A\u7EC4\u4EF6\uFF0C${build2.durationMs}ms`);
|
|
1999
2088
|
} catch (error) {
|
|
2089
|
+
this.lastBuildFailed = true;
|
|
2000
2090
|
this.logger.error(`[wxa-runner] \u7F16\u8BD1\u5931\u8D25\uFF1A
|
|
2001
2091
|
${error.message}`);
|
|
2002
2092
|
}
|
|
2003
2093
|
const server = import_http.default.createServer(this.app);
|
|
2004
|
-
this.sockets = new
|
|
2094
|
+
this.sockets = new import_ws3.WebSocketServer({ noServer: true, maxPayload: 64 * 1024 });
|
|
2005
2095
|
this.sockets.on("connection", (socket) => {
|
|
2006
2096
|
socket.on("error", () => void 0);
|
|
2007
2097
|
if (this.options.forwardConsole) printBrowserReports(socket, this.logger);
|
|
2008
2098
|
});
|
|
2099
|
+
this.socketProxy = createSocketProxy();
|
|
2009
2100
|
server.on("upgrade", (req, socket, head) => {
|
|
2101
|
+
if (req.url === "/__wxa__/socket") {
|
|
2102
|
+
this.socketProxy.handleUpgrade(req, socket, head, (ws) => this.socketProxy.emit("connection", ws, req));
|
|
2103
|
+
return;
|
|
2104
|
+
}
|
|
2010
2105
|
if (req.url?.startsWith("/__wxa__/ws")) {
|
|
2011
2106
|
this.sockets.handleUpgrade(req, socket, head, (ws) => this.sockets.emit("connection", ws, req));
|
|
2012
2107
|
} else {
|
|
@@ -2014,11 +2109,17 @@ ${error.message}`);
|
|
|
2014
2109
|
}
|
|
2015
2110
|
});
|
|
2016
2111
|
const host = this.options.host || "localhost";
|
|
2017
|
-
|
|
2112
|
+
let port;
|
|
2113
|
+
try {
|
|
2114
|
+
port = await listen(server, this.options.port, host, this.logger);
|
|
2115
|
+
} catch (error) {
|
|
2116
|
+
await this.watcher?.close();
|
|
2117
|
+
this.watcher = null;
|
|
2118
|
+
throw error;
|
|
2119
|
+
}
|
|
2018
2120
|
this.server = server;
|
|
2019
2121
|
this.lanAccess = LOCAL_HOST_OF_ANY_ADDRESS.has(host);
|
|
2020
2122
|
this.address = `http://${LOCAL_HOST_OF_ANY_ADDRESS.get(host) ?? host}:${port}`;
|
|
2021
|
-
if (this.options.watch !== false) this.startWatching();
|
|
2022
2123
|
this.ticketSource?.().then(requireUsableTicket).catch((error) => this.logger.warn(`[wxa-runner] \u5F00\u53D1\u8005\u5DE5\u5177\u7684\u767B\u5F55\u6001\u6682\u4E0D\u53EF\u7528\uFF08--devtools-login\uFF09\uFF1A${error.message}`));
|
|
2023
2124
|
return this.address;
|
|
2024
2125
|
}
|
|
@@ -2026,6 +2127,8 @@ ${error.message}`);
|
|
|
2026
2127
|
await this.watcher?.close();
|
|
2027
2128
|
this.sockets?.clients.forEach((client) => client.terminate());
|
|
2028
2129
|
this.sockets?.close();
|
|
2130
|
+
this.socketProxy?.clients.forEach((client) => client.terminate());
|
|
2131
|
+
this.socketProxy?.close();
|
|
2029
2132
|
const server = this.server;
|
|
2030
2133
|
this.server = null;
|
|
2031
2134
|
if (server) {
|
|
@@ -2056,6 +2159,7 @@ ${error.message}`);
|
|
|
2056
2159
|
baseLibVersion: this.baseLib.version,
|
|
2057
2160
|
device: this.device,
|
|
2058
2161
|
devtoolsLogin: this.devtoolsLogin,
|
|
2162
|
+
socketProxy: true,
|
|
2059
2163
|
forwardConsole: this.options.forwardConsole ?? false,
|
|
2060
2164
|
webViewWindow: this.options.webViewWindow ?? false
|
|
2061
2165
|
};
|
|
@@ -2252,36 +2356,37 @@ ${error.message}`);
|
|
|
2252
2356
|
get hotEnabled() {
|
|
2253
2357
|
return this.options.watch !== false;
|
|
2254
2358
|
}
|
|
2359
|
+
/** 返回初次扫描完成的时刻,此前已存在的文件不会作为改动报告 */
|
|
2255
2360
|
startWatching() {
|
|
2256
|
-
let lastBuildFailed = false;
|
|
2257
2361
|
const watched = [this.project.root];
|
|
2258
2362
|
const outsideRoot = (file) => import_path6.default.relative(this.project.root, file).startsWith("..");
|
|
2259
2363
|
if (this.setupFile && outsideRoot(this.setupFile)) watched.push(this.setupFile);
|
|
2260
2364
|
const projectConfig = import_path6.default.join(this.project.projectPath, "project.config.json");
|
|
2261
2365
|
if (outsideRoot(projectConfig) && import_fs6.default.existsSync(projectConfig)) watched.push(projectConfig);
|
|
2262
2366
|
this.watcher = watchProject(this.project.root, watched, async ({ files, structural }) => {
|
|
2263
|
-
const reloadOnly = structural || lastBuildFailed;
|
|
2367
|
+
const reloadOnly = structural || this.lastBuildFailed;
|
|
2264
2368
|
this.builder.invalidate(files);
|
|
2265
2369
|
const label = files.length > 3 ? `${files.slice(0, 3).join(", ")} \u7B49 ${files.length} \u4E2A\u6587\u4EF6` : files.join(", ");
|
|
2266
2370
|
try {
|
|
2267
2371
|
const build2 = await this.builder.build();
|
|
2268
|
-
lastBuildFailed = false;
|
|
2372
|
+
this.lastBuildFailed = false;
|
|
2269
2373
|
const plan = reloadOnly ? null : planHotUpdate(files, build2);
|
|
2270
2374
|
this.logger.log(`[wxa-runner] ${label} \u5DF2\u66F4\u65B0\uFF0C\u91CD\u65B0\u7F16\u8BD1 ${build2.durationMs}ms${plan ? "\uFF0C\u70ED\u66F4\u65B0" : ""}`);
|
|
2271
2375
|
this.broadcast(plan ? { type: "hot", version: build2.version, ...plan } : { type: "reload" });
|
|
2272
2376
|
} catch (error) {
|
|
2273
|
-
lastBuildFailed = true;
|
|
2377
|
+
this.lastBuildFailed = true;
|
|
2274
2378
|
const message = error.message;
|
|
2275
2379
|
this.logger.error(`[wxa-runner] \u7F16\u8BD1\u5931\u8D25\uFF1A
|
|
2276
2380
|
${message}`);
|
|
2277
2381
|
this.broadcast({ type: "error", message });
|
|
2278
2382
|
}
|
|
2279
2383
|
});
|
|
2384
|
+
return this.watcher.ready;
|
|
2280
2385
|
}
|
|
2281
2386
|
broadcast(message) {
|
|
2282
2387
|
const data = JSON.stringify(message);
|
|
2283
2388
|
this.sockets?.clients.forEach((client) => {
|
|
2284
|
-
if (client.readyState ===
|
|
2389
|
+
if (client.readyState === import_ws3.WebSocket.OPEN) client.send(data);
|
|
2285
2390
|
});
|
|
2286
2391
|
}
|
|
2287
2392
|
};
|