@weapp-vite/miniprogram-automator 1.2.14 → 1.2.15
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 +2 -2
- package/dist/index.mjs +135 -35
- package/dist/{launch-DKcPk1N2.mjs → launch-Dqnd-Lqe.mjs} +116 -18
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -351,10 +351,10 @@ declare class MiniProgram extends EventEmitter {
|
|
|
351
351
|
close(): Promise<void>;
|
|
352
352
|
remote(auto?: boolean): Promise<void>;
|
|
353
353
|
disconnect(): void;
|
|
354
|
-
enableLog(): Promise<void>;
|
|
354
|
+
enableLog(timeout?: number): Promise<void>;
|
|
355
355
|
on(event: string | symbol, listener: (...args: any[]) => void): this;
|
|
356
356
|
exposeFunction(name: string, bindingFunction: AutomatorCallable): Promise<void>;
|
|
357
|
-
checkVersion(): Promise<void>;
|
|
357
|
+
checkVersion(timeout?: number): Promise<void>;
|
|
358
358
|
/**
|
|
359
359
|
* @description 等待小程序 App 域协议可用,避免返回半就绪自动化会话。
|
|
360
360
|
*/
|
package/dist/index.mjs
CHANGED
|
@@ -217,10 +217,6 @@ function cmpVersion(versionA, versionB) {
|
|
|
217
217
|
}
|
|
218
218
|
return 0;
|
|
219
219
|
}
|
|
220
|
-
/** toStr 的方法封装。 */
|
|
221
|
-
function toStr(value) {
|
|
222
|
-
return value == null ? "" : String(value);
|
|
223
|
-
}
|
|
224
220
|
//#endregion
|
|
225
221
|
//#region src/pageRouteSnapshot.ts
|
|
226
222
|
const ROUTE_ELEMENT_SNAPSHOT_TIMEOUT = 5e3;
|
|
@@ -946,7 +942,7 @@ var Connection = class Connection extends EventEmitter {
|
|
|
946
942
|
//#endregion
|
|
947
943
|
//#region src/headless.ts
|
|
948
944
|
async function launchHeadlessAutomator(options) {
|
|
949
|
-
return await (await import("./launch-
|
|
945
|
+
return await (await import("./launch-Dqnd-Lqe.mjs")).launch({ projectPath: options.projectPath });
|
|
950
946
|
}
|
|
951
947
|
//#endregion
|
|
952
948
|
//#region src/launcher/portLease.ts
|
|
@@ -1044,8 +1040,64 @@ async function acquireAutomatorPortLease(preferredPort) {
|
|
|
1044
1040
|
return createLease(await getPort(0, "127.0.0.1"));
|
|
1045
1041
|
}
|
|
1046
1042
|
//#endregion
|
|
1043
|
+
//#region src/launcher/wechatCliFallback.ts
|
|
1044
|
+
const WECHAT_DEVTOOLS_SERVICE_PORT_RE = /listening\s+on\s+http:\/\/127\.0\.0\.1:(\d{2,5})/i;
|
|
1045
|
+
function extractWechatDevtoolsServicePort(output) {
|
|
1046
|
+
const port = Number(output.match(WECHAT_DEVTOOLS_SERVICE_PORT_RE)?.[1]);
|
|
1047
|
+
return Number.isInteger(port) && port > 0 && port <= 65535 ? port : void 0;
|
|
1048
|
+
}
|
|
1049
|
+
async function enableAutomatorViaHttp(options) {
|
|
1050
|
+
const endpoint = new URL("/auto", `http://127.0.0.1:${options.servicePort}`);
|
|
1051
|
+
endpoint.searchParams.set("project", options.projectPath);
|
|
1052
|
+
endpoint.searchParams.set("port", String(options.autoPort));
|
|
1053
|
+
endpoint.searchParams.set("autoPort", String(options.autoPort));
|
|
1054
|
+
if (options.account) endpoint.searchParams.set("account", options.account);
|
|
1055
|
+
if (options.ticket) endpoint.searchParams.set("ticket", options.ticket);
|
|
1056
|
+
if (options.trustProject) endpoint.searchParams.set("trustProject", "true");
|
|
1057
|
+
const response = await fetch(endpoint, { redirect: "follow" });
|
|
1058
|
+
const body = await response.text();
|
|
1059
|
+
if (!response.ok) throw new Error(`WeChat DevTools HTTP automator fallback failed with status ${response.status}${body.trim() ? `: ${body.trim().slice(0, 400)}` : ""}`);
|
|
1060
|
+
let result;
|
|
1061
|
+
try {
|
|
1062
|
+
result = JSON.parse(body);
|
|
1063
|
+
} catch (error) {
|
|
1064
|
+
throw new Error("WeChat DevTools HTTP automator fallback returned invalid JSON", { cause: error });
|
|
1065
|
+
}
|
|
1066
|
+
if (result && typeof result === "object" && "autoPort" in result) {
|
|
1067
|
+
const autoPort = Number(result.autoPort);
|
|
1068
|
+
if (!Number.isInteger(autoPort) || autoPort <= 0 || autoPort > 65535) throw new Error(`WeChat DevTools HTTP automator fallback returned invalid autoPort: ${String(result.autoPort)}`);
|
|
1069
|
+
return autoPort;
|
|
1070
|
+
}
|
|
1071
|
+
if (typeof result === "string" && /^s\d+$/.test(result)) return options.autoPort;
|
|
1072
|
+
throw new Error(`WeChat DevTools HTTP automator fallback returned unsupported response: ${body.trim().slice(0, 400)}`);
|
|
1073
|
+
}
|
|
1074
|
+
const AUTOMATOR_VALUE_OPTIONS = /* @__PURE__ */ new Set([
|
|
1075
|
+
"--auto-account",
|
|
1076
|
+
"--auto-port",
|
|
1077
|
+
"--autoAccount",
|
|
1078
|
+
"--autoPort",
|
|
1079
|
+
"--project",
|
|
1080
|
+
"--test-ticket",
|
|
1081
|
+
"--ticket"
|
|
1082
|
+
]);
|
|
1083
|
+
const AUTOMATOR_FLAG_OPTIONS = /* @__PURE__ */ new Set(["--trust-project"]);
|
|
1084
|
+
function resolveWechatDevtoolsBootstrapArgs(args) {
|
|
1085
|
+
const bootstrapArgs = [];
|
|
1086
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
1087
|
+
const arg = args[index];
|
|
1088
|
+
if (AUTOMATOR_VALUE_OPTIONS.has(arg)) {
|
|
1089
|
+
index += 1;
|
|
1090
|
+
continue;
|
|
1091
|
+
}
|
|
1092
|
+
if (AUTOMATOR_FLAG_OPTIONS.has(arg) || arg === "auto") continue;
|
|
1093
|
+
bootstrapArgs.push(arg);
|
|
1094
|
+
}
|
|
1095
|
+
bootstrapArgs.push("islogin");
|
|
1096
|
+
return bootstrapArgs;
|
|
1097
|
+
}
|
|
1098
|
+
//#endregion
|
|
1047
1099
|
//#region package.json
|
|
1048
|
-
var version = "1.2.
|
|
1100
|
+
var version = "1.2.15";
|
|
1049
1101
|
//#endregion
|
|
1050
1102
|
//#region src/Native.ts
|
|
1051
1103
|
/** Native 的实现。 */
|
|
@@ -2447,8 +2499,9 @@ var MiniProgram = class extends EventEmitter {
|
|
|
2447
2499
|
disconnect() {
|
|
2448
2500
|
this.connection.dispose();
|
|
2449
2501
|
}
|
|
2450
|
-
async enableLog() {
|
|
2451
|
-
await this.send("App.enableLog");
|
|
2502
|
+
async enableLog(timeout) {
|
|
2503
|
+
if (timeout === void 0) await this.send("App.enableLog");
|
|
2504
|
+
else await this.send("App.enableLog", {}, { timeout });
|
|
2452
2505
|
this.logEnabled = true;
|
|
2453
2506
|
}
|
|
2454
2507
|
on(event, listener) {
|
|
@@ -2461,8 +2514,8 @@ var MiniProgram = class extends EventEmitter {
|
|
|
2461
2514
|
this.appBindings.set(name, bindingFunction);
|
|
2462
2515
|
await this.send("App.addBinding", { name });
|
|
2463
2516
|
}
|
|
2464
|
-
async checkVersion() {
|
|
2465
|
-
const toolInfo = await this.send("Tool.getInfo");
|
|
2517
|
+
async checkVersion(timeout) {
|
|
2518
|
+
const toolInfo = timeout === void 0 ? await this.send("Tool.getInfo") : await this.send("Tool.getInfo", {}, { timeout });
|
|
2466
2519
|
this.connection.configureToolInfo(toolInfo);
|
|
2467
2520
|
const sdkVersion = toolInfo.SDKVersion;
|
|
2468
2521
|
if (typeof sdkVersion !== "string" || !sdkVersion.trim()) return;
|
|
@@ -2474,12 +2527,16 @@ var MiniProgram = class extends EventEmitter {
|
|
|
2474
2527
|
async waitForAppReady(timeout = APP_READY_TIMEOUT) {
|
|
2475
2528
|
const startedAt = Date.now();
|
|
2476
2529
|
let lastError;
|
|
2477
|
-
while (Date.now() - startedAt
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2530
|
+
while (Date.now() - startedAt < timeout) {
|
|
2531
|
+
const remainingTimeout = timeout - (Date.now() - startedAt);
|
|
2532
|
+
try {
|
|
2533
|
+
await this.send("App.captureScreenshot", {}, { timeout: Math.min(APP_READY_PROBE_TIMEOUT, remainingTimeout) });
|
|
2534
|
+
return;
|
|
2535
|
+
} catch (error) {
|
|
2536
|
+
lastError = error;
|
|
2537
|
+
const remainingAfterProbe = timeout - (Date.now() - startedAt);
|
|
2538
|
+
if (remainingAfterProbe > 0) await sleep(Math.min(APP_READY_POLL_DELAY, remainingAfterProbe));
|
|
2539
|
+
}
|
|
2483
2540
|
}
|
|
2484
2541
|
throw lastError instanceof Error ? lastError : /* @__PURE__ */ new Error(`Timed out waiting App domain readiness after ${timeout}ms`);
|
|
2485
2542
|
}
|
|
@@ -3128,6 +3185,7 @@ var SwanLauncher = class {
|
|
|
3128
3185
|
* @file 开发者工具启动与连接流程。
|
|
3129
3186
|
*/
|
|
3130
3187
|
const DEFAULT_TIMEOUT = 3e4;
|
|
3188
|
+
const VERSION_CHECK_TIMEOUT = 3e4;
|
|
3131
3189
|
const AUTOMATOR_LAUNCH_RETRIES = 3;
|
|
3132
3190
|
const DEFAULT_RUNTIME_PROVIDER_ENV = "WEAPP_VITE_AUTOMATOR_RUNTIME_PROVIDER";
|
|
3133
3191
|
const LEGACY_RUNTIME_PROVIDER_ENV = "WEAPP_VITE_E2E_RUNTIME_PROVIDER";
|
|
@@ -3243,24 +3301,23 @@ var Launcher = class {
|
|
|
3243
3301
|
let processError = null;
|
|
3244
3302
|
let processExitCode = null;
|
|
3245
3303
|
let processSignal = null;
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
toStr(port)
|
|
3253
|
-
];
|
|
3254
|
-
if (account) args.push("--auto-account", account);
|
|
3255
|
-
else if (ticket) args.push("--ticket", ticket);
|
|
3256
|
-
if (trustProject) args.push("--trust-project");
|
|
3304
|
+
let successfulCliExitSettled = false;
|
|
3305
|
+
let httpFallbackAttempted = false;
|
|
3306
|
+
let httpFallbackError = null;
|
|
3307
|
+
let targetPort = port;
|
|
3308
|
+
const cliOutput = [];
|
|
3309
|
+
args = resolveWechatDevtoolsBootstrapArgs(args);
|
|
3257
3310
|
try {
|
|
3258
3311
|
const spawnTarget = shouldUseWindowsCommandShell(cliPath) ? resolveWindowsBatchSpawn(cliPath, args) : {
|
|
3259
3312
|
file: cliPath,
|
|
3260
3313
|
args
|
|
3261
3314
|
};
|
|
3262
3315
|
const child = spawn(spawnTarget.file, spawnTarget.args, {
|
|
3263
|
-
stdio:
|
|
3316
|
+
stdio: [
|
|
3317
|
+
"ignore",
|
|
3318
|
+
"pipe",
|
|
3319
|
+
"pipe"
|
|
3320
|
+
],
|
|
3264
3321
|
cwd: cwd || void 0,
|
|
3265
3322
|
...shouldUseWindowsCommandShell(cliPath) ? {
|
|
3266
3323
|
windowsHide: true,
|
|
@@ -3270,10 +3327,17 @@ var Launcher = class {
|
|
|
3270
3327
|
child.on("error", (error) => {
|
|
3271
3328
|
processError = error;
|
|
3272
3329
|
});
|
|
3330
|
+
child.stdout?.on("data", (chunk) => {
|
|
3331
|
+
cliOutput.push(String(chunk));
|
|
3332
|
+
});
|
|
3333
|
+
child.stderr?.on("data", (chunk) => {
|
|
3334
|
+
cliOutput.push(String(chunk));
|
|
3335
|
+
});
|
|
3273
3336
|
child.on("exit", (code, signal) => {
|
|
3274
3337
|
processExitCode = code;
|
|
3275
3338
|
processSignal = signal;
|
|
3276
3339
|
if (code !== 0 || signal) processError = /* @__PURE__ */ new Error(`DevTools cli exited unexpectedly with code ${code ?? "null"}${signal ? ` and signal ${signal}` : ""}`);
|
|
3340
|
+
else successfulCliExitSettled = true;
|
|
3277
3341
|
});
|
|
3278
3342
|
child.unref();
|
|
3279
3343
|
} catch (error) {
|
|
@@ -3281,16 +3345,51 @@ var Launcher = class {
|
|
|
3281
3345
|
}
|
|
3282
3346
|
let miniProgram = null;
|
|
3283
3347
|
let lastConnectError = null;
|
|
3348
|
+
const readinessStartedAt = Date.now();
|
|
3349
|
+
const resolveRemainingTimeout = () => Math.max(0, timeout - (Date.now() - readinessStartedAt));
|
|
3284
3350
|
await waitUntil(async () => {
|
|
3285
3351
|
try {
|
|
3286
3352
|
if (processError) return true;
|
|
3353
|
+
if (successfulCliExitSettled && !httpFallbackAttempted) {
|
|
3354
|
+
const servicePort = extractWechatDevtoolsServicePort(cliOutput.join("\n"));
|
|
3355
|
+
if (servicePort) {
|
|
3356
|
+
httpFallbackAttempted = true;
|
|
3357
|
+
try {
|
|
3358
|
+
targetPort = await enableAutomatorViaHttp({
|
|
3359
|
+
account,
|
|
3360
|
+
autoPort: port,
|
|
3361
|
+
projectPath: resolvedProjectPath,
|
|
3362
|
+
servicePort,
|
|
3363
|
+
ticket,
|
|
3364
|
+
trustProject
|
|
3365
|
+
});
|
|
3366
|
+
} catch (error) {
|
|
3367
|
+
httpFallbackError = error;
|
|
3368
|
+
return true;
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
}
|
|
3372
|
+
const connectTimeout = resolveRemainingTimeout();
|
|
3373
|
+
if (connectTimeout <= 0) return false;
|
|
3287
3374
|
const candidate = await this.connectTool({
|
|
3288
|
-
timeout: 3e3,
|
|
3289
|
-
wsEndpoint: `ws://127.0.0.1:${
|
|
3375
|
+
timeout: Math.min(3e3, connectTimeout),
|
|
3376
|
+
wsEndpoint: `ws://127.0.0.1:${targetPort}`
|
|
3290
3377
|
});
|
|
3291
3378
|
try {
|
|
3292
|
-
|
|
3293
|
-
if (
|
|
3379
|
+
const checkVersionTimeout = resolveRemainingTimeout();
|
|
3380
|
+
if (checkVersionTimeout <= 0) {
|
|
3381
|
+
candidate.disconnect();
|
|
3382
|
+
return false;
|
|
3383
|
+
}
|
|
3384
|
+
await candidate.checkVersion(Math.min(VERSION_CHECK_TIMEOUT, checkVersionTimeout));
|
|
3385
|
+
if (typeof candidate.waitForAppReady === "function") {
|
|
3386
|
+
const appReadyTimeout = resolveRemainingTimeout();
|
|
3387
|
+
if (appReadyTimeout <= 0) {
|
|
3388
|
+
candidate.disconnect();
|
|
3389
|
+
return false;
|
|
3390
|
+
}
|
|
3391
|
+
await candidate.waitForAppReady(appReadyTimeout);
|
|
3392
|
+
}
|
|
3294
3393
|
} catch (error) {
|
|
3295
3394
|
candidate.disconnect();
|
|
3296
3395
|
lastConnectError = error;
|
|
@@ -3305,6 +3404,7 @@ var Launcher = class {
|
|
|
3305
3404
|
}
|
|
3306
3405
|
}, timeout, 1e3);
|
|
3307
3406
|
if (!miniProgram) {
|
|
3407
|
+
if (httpFallbackError) throw httpFallbackError;
|
|
3308
3408
|
if (processError) throw new Error("Failed to launch wechat web devTools, please make sure cliPath is correctly specified");
|
|
3309
3409
|
if (lastConnectError) throw lastConnectError;
|
|
3310
3410
|
if (processExitCode !== null || processSignal) throw new Error("Failed to launch wechat web devTools, please make sure http port is open");
|
|
@@ -3312,9 +3412,9 @@ var Launcher = class {
|
|
|
3312
3412
|
}
|
|
3313
3413
|
const resolvedMiniProgram = miniProgram;
|
|
3314
3414
|
Reflect.set(resolvedMiniProgram, "__WEAPP_VITE_SESSION_METADATA", {
|
|
3315
|
-
port,
|
|
3415
|
+
port: targetPort,
|
|
3316
3416
|
projectPath: resolvedProjectPath,
|
|
3317
|
-
wsEndpoint: `ws://127.0.0.1:${
|
|
3417
|
+
wsEndpoint: `ws://127.0.0.1:${targetPort}`
|
|
3318
3418
|
});
|
|
3319
3419
|
releasePortLeaseOnExit = !retainPortLeaseUntilSessionClose(resolvedMiniProgram, portLease);
|
|
3320
3420
|
await sleep$1(5e3);
|
|
@@ -3326,7 +3426,7 @@ var Launcher = class {
|
|
|
3326
3426
|
async connect(options) {
|
|
3327
3427
|
if (normalizePlatform(options.platform) === "swan") return await new SwanLauncher().connect(options);
|
|
3328
3428
|
const miniProgram = await this.connectTool(options);
|
|
3329
|
-
await miniProgram.checkVersion();
|
|
3429
|
+
await miniProgram.checkVersion(options.timeout);
|
|
3330
3430
|
return miniProgram;
|
|
3331
3431
|
}
|
|
3332
3432
|
async extendProjectConfig(projectConfig, projectPath) {
|
|
@@ -12036,6 +12036,42 @@ function resolveTemplateData(node, source) {
|
|
|
12036
12036
|
return resolved && typeof resolved === "object" ? resolved : {};
|
|
12037
12037
|
}
|
|
12038
12038
|
//#endregion
|
|
12039
|
+
//#region ../../mpcore/packages/simulator/src/project/plugins.ts
|
|
12040
|
+
const HEADLESS_PLUGIN_VIRTUAL_ROOT = "__plugins__";
|
|
12041
|
+
const PLUGIN_URL_RE = /^plugin:\/\/([^/]+)\/(.+)$/;
|
|
12042
|
+
function createPluginVirtualRoot(alias) {
|
|
12043
|
+
return `${HEADLESS_PLUGIN_VIRTUAL_ROOT}/${alias}`;
|
|
12044
|
+
}
|
|
12045
|
+
function resolvePluginRequest(plugins, request, kind) {
|
|
12046
|
+
const match = PLUGIN_URL_RE.exec(request);
|
|
12047
|
+
if (!match) return;
|
|
12048
|
+
const [, alias, publicName] = match;
|
|
12049
|
+
const plugin = plugins.find((item) => item.alias === alias);
|
|
12050
|
+
const registry = kind === "page" ? plugin?.config.pages : plugin?.config.publicComponents;
|
|
12051
|
+
const resourcePath = registry && typeof registry === "object" && !Array.isArray(registry) ? registry[publicName] : void 0;
|
|
12052
|
+
if (!plugin || typeof resourcePath !== "string" || !resourcePath) return;
|
|
12053
|
+
return {
|
|
12054
|
+
plugin,
|
|
12055
|
+
publicName,
|
|
12056
|
+
resourcePath: `${plugin.virtualRoot}/${resourcePath}`
|
|
12057
|
+
};
|
|
12058
|
+
}
|
|
12059
|
+
function createPluginArtifactSource(fallback, miniprogramRootPath, plugins) {
|
|
12060
|
+
function resolvePhysicalPath(filePath) {
|
|
12061
|
+
const normalizedPath = path.resolve(filePath);
|
|
12062
|
+
for (const plugin of plugins) {
|
|
12063
|
+
const virtualRootPath = path.resolve(miniprogramRootPath, plugin.virtualRoot);
|
|
12064
|
+
const relativePath = path.relative(virtualRootPath, normalizedPath);
|
|
12065
|
+
if (!relativePath.startsWith("..") && !path.isAbsolute(relativePath)) return path.resolve(plugin.rootPath, relativePath);
|
|
12066
|
+
}
|
|
12067
|
+
return normalizedPath;
|
|
12068
|
+
}
|
|
12069
|
+
return {
|
|
12070
|
+
has: (filePath) => fallback.has(resolvePhysicalPath(filePath)),
|
|
12071
|
+
readText: (filePath) => fallback.readText(resolvePhysicalPath(filePath))
|
|
12072
|
+
};
|
|
12073
|
+
}
|
|
12074
|
+
//#endregion
|
|
12039
12075
|
//#region ../../mpcore/packages/simulator/src/view/eventBinding.ts
|
|
12040
12076
|
const LEGACY_EVENT_NAME_RE = /^\w+$/;
|
|
12041
12077
|
const EVENT_BINDING_PREFIXES = [
|
|
@@ -14583,11 +14619,12 @@ function isMustacheOnly(value) {
|
|
|
14583
14619
|
function toDatasetKey$3(attributeName) {
|
|
14584
14620
|
return attributeName.slice(5).replace(DATASET_NAME_RE$3, (_match, char) => char.toUpperCase());
|
|
14585
14621
|
}
|
|
14586
|
-
function collectDataset$3(node) {
|
|
14622
|
+
function collectDataset$3(node, source) {
|
|
14587
14623
|
const dataset = {};
|
|
14588
14624
|
for (const [key, value] of Object.entries(node.attribs ?? {})) {
|
|
14589
14625
|
if (!key.startsWith("data-") || key === "data-sim-scope" || key === "data-sim-tap" || key === "data-sim-component") continue;
|
|
14590
|
-
|
|
14626
|
+
const resolvedValue = source && isMustacheOnly(value) ? resolveTemplateExpression(source, value) : value;
|
|
14627
|
+
dataset[toDatasetKey$3(key)] = String(resolvedValue ?? "");
|
|
14591
14628
|
}
|
|
14592
14629
|
return dataset;
|
|
14593
14630
|
}
|
|
@@ -14698,7 +14735,7 @@ function createLoopScope(scope, itemName, indexName, item, index) {
|
|
|
14698
14735
|
//#endregion
|
|
14699
14736
|
//#region ../../mpcore/packages/simulator/src/runtime/render/component.ts
|
|
14700
14737
|
function resolveComponentRegistryEntry(context, ownerJsonPath, ownerFilePath, alias, genericComponentBasePath) {
|
|
14701
|
-
const usingComponents = resolveUsingComponents(context
|
|
14738
|
+
const usingComponents = resolveUsingComponents(context, ownerJsonPath, ownerFilePath);
|
|
14702
14739
|
const componentBasePath = genericComponentBasePath ?? usingComponents.get(alias);
|
|
14703
14740
|
if (!componentBasePath) return null;
|
|
14704
14741
|
const filePath = `${componentBasePath}.js`;
|
|
@@ -14720,14 +14757,14 @@ function readComponentConfig(artifactSource, jsonPath) {
|
|
|
14720
14757
|
return {};
|
|
14721
14758
|
}
|
|
14722
14759
|
}
|
|
14723
|
-
function resolveUsingComponents(
|
|
14760
|
+
function resolveUsingComponents(context, ownerJsonPath, ownerFilePath) {
|
|
14724
14761
|
try {
|
|
14725
|
-
const usingComponents = readComponentConfig(artifactSource, ownerJsonPath).usingComponents;
|
|
14762
|
+
const usingComponents = readComponentConfig(context.artifactSource, ownerJsonPath).usingComponents;
|
|
14726
14763
|
if (!usingComponents || typeof usingComponents !== "object" || Array.isArray(usingComponents)) return /* @__PURE__ */ new Map();
|
|
14727
14764
|
const resolved = /* @__PURE__ */ new Map();
|
|
14728
14765
|
for (const [alias, rawPath] of Object.entries(usingComponents)) {
|
|
14729
14766
|
if (typeof rawPath !== "string") continue;
|
|
14730
|
-
const basePath = rawPath.startsWith("/") ? rawPath.replace(LEADING_SLASH_RE$4, "") : path.posix.normalize(path.posix.join(path.posix.dirname(ownerFilePath), rawPath));
|
|
14767
|
+
const basePath = resolvePluginRequest(context.project.plugins, rawPath, "publicComponent")?.resourcePath ?? (rawPath.startsWith("/") ? rawPath.replace(LEADING_SLASH_RE$4, "") : path.posix.normalize(path.posix.join(path.posix.dirname(ownerFilePath), rawPath)));
|
|
14731
14768
|
resolved.set(alias, basePath.replace(LEADING_SLASH_RE$4, ""));
|
|
14732
14769
|
}
|
|
14733
14770
|
return resolved;
|
|
@@ -14739,7 +14776,7 @@ function resolveComponentGenerics(context, hostNode, ownerJsonPath, ownerFilePat
|
|
|
14739
14776
|
const componentJsonPath = path.resolve(context.project.miniprogramRootPath, `${componentFilePath.replace(JS_FILE_RE, "")}.json`);
|
|
14740
14777
|
const componentGenerics = readComponentConfig(context.artifactSource, componentJsonPath).componentGenerics;
|
|
14741
14778
|
if (!componentGenerics || typeof componentGenerics !== "object" || Array.isArray(componentGenerics)) return;
|
|
14742
|
-
const ownerComponents = resolveUsingComponents(context
|
|
14779
|
+
const ownerComponents = resolveUsingComponents(context, ownerJsonPath, ownerFilePath);
|
|
14743
14780
|
const resolved = /* @__PURE__ */ new Map();
|
|
14744
14781
|
for (const [genericName, definition] of Object.entries(componentGenerics)) {
|
|
14745
14782
|
const selectedAlias = hostNode.attribs?.[`generic:${genericName}`];
|
|
@@ -14764,9 +14801,10 @@ function buildComponentTrigger(componentScopeId, context, hostNode) {
|
|
|
14764
14801
|
return (instance, eventName, detail, triggerOptions) => {
|
|
14765
14802
|
const interactionTarget = instance.__lastInteractionEvent__?.target;
|
|
14766
14803
|
const interactionCurrentTarget = instance.__lastInteractionEvent__?.currentTarget;
|
|
14804
|
+
const componentDataset = context.componentScopes.get(componentScopeId)?.dataset ?? hostDataset;
|
|
14767
14805
|
const interactionMark = instance.__lastInteractionEvent__?.mark;
|
|
14768
14806
|
const target = {
|
|
14769
|
-
dataset: interactionTarget?.dataset ??
|
|
14807
|
+
dataset: interactionTarget?.dataset ?? componentDataset,
|
|
14770
14808
|
id: interactionTarget?.id ?? hostId
|
|
14771
14809
|
};
|
|
14772
14810
|
let currentScopeId = componentScopeId;
|
|
@@ -14822,7 +14860,7 @@ function createComponentScope(clonedNode, scope, componentScopeId, componentInst
|
|
|
14822
14860
|
alias: clonedNode.name,
|
|
14823
14861
|
classList: String(clonedNode.attribs?.class ?? "").split(CLASS_SPLIT_RE).map((item) => item.trim()).filter(Boolean),
|
|
14824
14862
|
data: createMergedScopeData(scope.data, componentInstance.properties, componentInstance.data),
|
|
14825
|
-
dataset: collectDataset$3(clonedNode),
|
|
14863
|
+
dataset: collectDataset$3(clonedNode, scope.data),
|
|
14826
14864
|
eventBindings: collectComponentEventBindings(clonedNode),
|
|
14827
14865
|
getMethod: (methodName) => {
|
|
14828
14866
|
const method = componentInstance?.[methodName];
|
|
@@ -15051,7 +15089,8 @@ function renderNodeTree(node, scope, context, ownerJsonPath, ownerFilePath, inst
|
|
|
15051
15089
|
}
|
|
15052
15090
|
function renderRuntimePageTree(context, page) {
|
|
15053
15091
|
const route = page.route.replace(LEADING_SLASH_RE$4, "");
|
|
15054
|
-
const
|
|
15092
|
+
const resourcePath = context.project.routes.find((item) => item.route === route)?.resourcePath ?? route;
|
|
15093
|
+
const templatePath = path.resolve(context.project.miniprogramRootPath, `${resourcePath}.wxml`);
|
|
15055
15094
|
const document = parseTemplateDocument(readTemplateSource(context.artifactSource, templatePath));
|
|
15056
15095
|
const pageScopeId = `page:${route}`;
|
|
15057
15096
|
const pageScope = {
|
|
@@ -15068,7 +15107,7 @@ function renderRuntimePageTree(context, page) {
|
|
|
15068
15107
|
const seenComponentScopes = /* @__PURE__ */ new Set();
|
|
15069
15108
|
const root = (document.children ?? [])[0] ?? document;
|
|
15070
15109
|
const templateRenderState = createTemplateRenderState(root);
|
|
15071
|
-
const renderedRoot = renderNodeTree(root, pageScope, context, path.resolve(context.project.miniprogramRootPath, `${
|
|
15110
|
+
const renderedRoot = renderNodeTree(root, pageScope, context, path.resolve(context.project.miniprogramRootPath, `${resourcePath}.json`), `${resourcePath}.js`, pageScopeId, seenComponentScopes, templateRenderState);
|
|
15072
15111
|
for (const [scopeId, instance] of [...context.componentCache.entries()]) if (!seenComponentScopes.has(scopeId)) {
|
|
15073
15112
|
runComponentLifecycle(instance, "detached");
|
|
15074
15113
|
context.componentCache.delete(scopeId);
|
|
@@ -15819,7 +15858,7 @@ function pushRoute(records, seen, record) {
|
|
|
15819
15858
|
seen.add(record.route);
|
|
15820
15859
|
records.push(record);
|
|
15821
15860
|
}
|
|
15822
|
-
function resolveRoutesFromAppConfig(config) {
|
|
15861
|
+
function resolveRoutesFromAppConfig(config, plugins = []) {
|
|
15823
15862
|
const records = [];
|
|
15824
15863
|
const seen = /* @__PURE__ */ new Set();
|
|
15825
15864
|
if (Array.isArray(config.pages)) for (const page of config.pages) {
|
|
@@ -15849,6 +15888,19 @@ function resolveRoutesFromAppConfig(config) {
|
|
|
15849
15888
|
});
|
|
15850
15889
|
}
|
|
15851
15890
|
}
|
|
15891
|
+
for (const plugin of plugins) {
|
|
15892
|
+
const pages = plugin.config.pages;
|
|
15893
|
+
if (!pages || typeof pages !== "object" || Array.isArray(pages)) continue;
|
|
15894
|
+
for (const resourcePath of Object.values(pages)) {
|
|
15895
|
+
if (typeof resourcePath !== "string" || !resourcePath) continue;
|
|
15896
|
+
pushRoute(records, seen, {
|
|
15897
|
+
kind: "page",
|
|
15898
|
+
resourcePath: `${plugin.virtualRoot}/${resourcePath}`,
|
|
15899
|
+
route: `plugin-private://${plugin.provider}/${resourcePath}`,
|
|
15900
|
+
source: "plugin"
|
|
15901
|
+
});
|
|
15902
|
+
}
|
|
15903
|
+
}
|
|
15852
15904
|
return records;
|
|
15853
15905
|
}
|
|
15854
15906
|
//#endregion
|
|
@@ -15860,9 +15912,10 @@ function createProjectDescriptor(options) {
|
|
|
15860
15912
|
appConfigPath: options.appConfigPath,
|
|
15861
15913
|
miniprogramRoot: options.miniprogramRoot,
|
|
15862
15914
|
miniprogramRootPath: options.miniprogramRootPath,
|
|
15915
|
+
plugins: options.plugins ?? [],
|
|
15863
15916
|
projectPath: options.projectPath,
|
|
15864
15917
|
projectConfigFiles: options.projectConfigFiles ?? [],
|
|
15865
|
-
routes: resolveRoutesFromAppConfig(options.appConfig)
|
|
15918
|
+
routes: resolveRoutesFromAppConfig(options.appConfig, options.plugins ?? [])
|
|
15866
15919
|
};
|
|
15867
15920
|
}
|
|
15868
15921
|
//#endregion
|
|
@@ -15979,6 +16032,36 @@ function resolveMiniprogramRoot(projectPath, configFiles) {
|
|
|
15979
16032
|
}
|
|
15980
16033
|
throw new Error(`Failed to resolve miniprogramRoot for headless runtime project: ${projectPath}. Expected project.config.json or project.private.config.json to define miniprogramRoot.`);
|
|
15981
16034
|
}
|
|
16035
|
+
function resolveConfiguredRoot(configFiles, key) {
|
|
16036
|
+
for (const configFile of [...configFiles].reverse()) {
|
|
16037
|
+
const value = configFile.value[key];
|
|
16038
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
16039
|
+
}
|
|
16040
|
+
}
|
|
16041
|
+
function resolveLocalPlugins(projectPath, projectConfigFiles, appConfig) {
|
|
16042
|
+
const pluginRoot = resolveConfiguredRoot(projectConfigFiles, "pluginRoot");
|
|
16043
|
+
const configuredPlugins = appConfig.plugins;
|
|
16044
|
+
if (!pluginRoot || !configuredPlugins || typeof configuredPlugins !== "object" || Array.isArray(configuredPlugins)) return [];
|
|
16045
|
+
const rootPath = path.resolve(projectPath, pluginRoot);
|
|
16046
|
+
const pluginConfig = readJsonObject$1(path.resolve(rootPath, "plugin.json"));
|
|
16047
|
+
if (!pluginConfig) return [];
|
|
16048
|
+
const plugins = [];
|
|
16049
|
+
const projectAppId = resolveConfiguredRoot(projectConfigFiles, "appid");
|
|
16050
|
+
for (const [alias, definition] of Object.entries(configuredPlugins)) {
|
|
16051
|
+
if (!definition || typeof definition !== "object" || Array.isArray(definition)) continue;
|
|
16052
|
+
const provider = definition.provider;
|
|
16053
|
+
const isLocalPlugin = definition.version === "dev" || projectAppId && provider === projectAppId;
|
|
16054
|
+
if (typeof provider !== "string" || !provider || !isLocalPlugin) continue;
|
|
16055
|
+
plugins.push({
|
|
16056
|
+
alias,
|
|
16057
|
+
config: pluginConfig,
|
|
16058
|
+
provider,
|
|
16059
|
+
rootPath,
|
|
16060
|
+
virtualRoot: createPluginVirtualRoot(alias)
|
|
16061
|
+
});
|
|
16062
|
+
}
|
|
16063
|
+
return plugins;
|
|
16064
|
+
}
|
|
15982
16065
|
function ensureFileExists(filePath, label) {
|
|
15983
16066
|
if (fs.existsSync(filePath)) return;
|
|
15984
16067
|
throw new Error(`Missing ${label} for headless runtime project: ${normalize(filePath)}`);
|
|
@@ -15997,11 +16080,15 @@ function loadProject(projectPath) {
|
|
|
15997
16080
|
ensureFileExists(miniprogramRootPath, "miniprogramRoot directory");
|
|
15998
16081
|
const appConfigPath = path.resolve(miniprogramRootPath, "app.json");
|
|
15999
16082
|
ensureFileExists(appConfigPath, "built app.json");
|
|
16083
|
+
const appConfig = loadAppConfig(appConfigPath);
|
|
16084
|
+
const plugins = resolveLocalPlugins(normalizedProjectPath, projectConfigFiles, appConfig);
|
|
16000
16085
|
return createProjectDescriptor({
|
|
16001
|
-
appConfig
|
|
16086
|
+
appConfig,
|
|
16002
16087
|
appConfigPath,
|
|
16088
|
+
artifactSource: createPluginArtifactSource(createFileSystemArtifactSource(), miniprogramRootPath, plugins),
|
|
16003
16089
|
miniprogramRoot,
|
|
16004
16090
|
miniprogramRootPath,
|
|
16091
|
+
plugins,
|
|
16005
16092
|
projectPath: normalizedProjectPath,
|
|
16006
16093
|
projectConfigFiles
|
|
16007
16094
|
});
|
|
@@ -17371,6 +17458,12 @@ function createModuleLoader(registries, getCurrentPages, getApp, wxDriver, optio
|
|
|
17371
17458
|
registries.currentLoadContext = previousLoadContext;
|
|
17372
17459
|
}
|
|
17373
17460
|
}
|
|
17461
|
+
executionContext.requirePlugin = (alias) => {
|
|
17462
|
+
const plugin = options.plugins.find((item) => item.alias === alias);
|
|
17463
|
+
if (!plugin) throw new Error(`Unknown local plugin "${alias}" in headless runtime.`);
|
|
17464
|
+
const main = typeof plugin.config.main === "string" && plugin.config.main ? plugin.config.main : "index.js";
|
|
17465
|
+
return executeModule(path.resolve(options.miniprogramRootPath, plugin.virtualRoot, main), null).exports;
|
|
17466
|
+
};
|
|
17374
17467
|
return {
|
|
17375
17468
|
close() {
|
|
17376
17469
|
moduleCache.clear();
|
|
@@ -19283,7 +19376,9 @@ var HeadlessSession = class {
|
|
|
19283
19376
|
artifactSource: this.project.artifactSource,
|
|
19284
19377
|
globals: options.globals,
|
|
19285
19378
|
kernel: this.kernel,
|
|
19286
|
-
|
|
19379
|
+
miniprogramRootPath: this.project.miniprogramRootPath,
|
|
19380
|
+
onConsole: (entry) => this.emit("console", entry),
|
|
19381
|
+
plugins: this.project.plugins
|
|
19287
19382
|
});
|
|
19288
19383
|
}
|
|
19289
19384
|
assertActive() {
|
|
@@ -19902,8 +19997,9 @@ var HeadlessSession = class {
|
|
|
19902
19997
|
});
|
|
19903
19998
|
}
|
|
19904
19999
|
createFreshPage(target) {
|
|
19905
|
-
const
|
|
19906
|
-
const
|
|
20000
|
+
const resourcePath = target.routeRecord.resourcePath ?? target.routeRecord.route;
|
|
20001
|
+
const pageModulePath = path.resolve(this.project.miniprogramRootPath, `${resourcePath}.js`);
|
|
20002
|
+
const pageConfigPath = path.resolve(this.project.miniprogramRootPath, `${resourcePath}.json`);
|
|
19907
20003
|
const pageDefinition = this.moduleLoader.executePageModule(pageModulePath, target.routeRecord.route);
|
|
19908
20004
|
const pageConfig = readJsonObject(this.project, pageConfigPath);
|
|
19909
20005
|
const pageInstance = createPageInstance(`/${target.routeRecord.route}`, pageDefinition, target.query, {
|
|
@@ -19938,7 +20034,9 @@ var HeadlessSession = class {
|
|
|
19938
20034
|
}
|
|
19939
20035
|
resolveNavigationTarget(url) {
|
|
19940
20036
|
const { pathname, query } = parseNavigationUrl(url);
|
|
19941
|
-
const
|
|
20037
|
+
const baseRoute = this.currentPageInstance ? stripLeadingSlash(this.currentPageInstance.route) : void 0;
|
|
20038
|
+
const pluginRequest = resolvePluginRequest(this.project.plugins, pathname, "page");
|
|
20039
|
+
const normalizedRoute = pluginRequest ? `plugin-private://${pluginRequest.plugin.provider}/${pluginRequest.resourcePath.slice(pluginRequest.plugin.virtualRoot.length + 1)}` : resolveNavigationPath(pathname, baseRoute);
|
|
19942
20040
|
const routeRecord = this.project.routes.find((item) => item.route === normalizedRoute);
|
|
19943
20041
|
if (!routeRecord) {
|
|
19944
20042
|
this.bootstrap(createAppLaunchOptions(normalizedRoute, query));
|
package/package.json
CHANGED