@unmagic/vms 0.0.3-beta.0 → 0.0.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.
@@ -9,14 +9,24 @@ import t__default from '@babel/types';
9
9
  import { generate } from '@babel/generator';
10
10
  import _traverse from '@babel/traverse';
11
11
  import { codeFrameColumns } from '@babel/code-frame';
12
- import { bold, red } from 'kolorist';
12
+ import { bold, red, green } from 'kolorist';
13
13
  import { createTransformContext, traverseNode } from '@vue/compiler-dom';
14
14
  import { fileURLToPath } from 'node:url';
15
15
  import { resolve } from 'path';
16
16
  import fs from 'fs-extra';
17
17
  import { pathToFileURL } from 'url';
18
18
  import { NodeTypes } from '@vue/compiler-core';
19
- import { transformFromAstSync } from '@babel/core';
19
+ import { transformFromAstSync, transformAsync, transformFileAsync } from '@babel/core';
20
+ import commonjs from '@rollup/plugin-commonjs';
21
+ import resolve$1 from '@rollup/plugin-node-resolve';
22
+ import replace from '@rollup/plugin-replace';
23
+ import terser from '@rollup/plugin-terser';
24
+ import chokidar from 'chokidar';
25
+ import { getPackageInfo } from 'local-pkg';
26
+ import process$1 from 'node:process';
27
+ import { rollup } from 'rollup';
28
+ import { minify } from 'terser';
29
+ import { performance } from 'perf_hooks';
20
30
 
21
31
  var version = "7.29.2";
22
32
  var pk = {
@@ -929,22 +939,22 @@ function checkSlotsUsage(templateContent) {
929
939
  return templateContent.includes('slot') || templateContent.includes('Slot');
930
940
  }
931
941
  /**
932
- * 确保 @vue-mini/core 中导入了指定的 specifierName。
933
- * 如果已存在则跳过,否则追加到已有的 @vue-mini/core import 或新建一个。
942
+ * 确保 @unmagic/vue-mini 中导入了指定的 specifierName。
943
+ * 如果已存在则跳过,否则追加到已有的 @unmagic/vue-mini import 或新建一个。
934
944
  */
935
945
  function ensureCoreImport(sfcContext, specifierName) {
936
- const hasImport = sfcContext.importAST.some((importNode) => importNode.source.value === '@vue-mini/core' &&
946
+ const hasImport = sfcContext.importAST.some((importNode) => importNode.source.value === '@unmagic/vue-mini' &&
937
947
  importNode.specifiers.some((spec) => t.isImportSpecifier(spec) &&
938
948
  t.isIdentifier(spec.imported) &&
939
949
  spec.imported.name === specifierName));
940
950
  if (hasImport)
941
951
  return;
942
- const vueImport = sfcContext.importAST.find((importNode) => t.isImportDeclaration(importNode) && importNode.source.value === '@vue-mini/core');
952
+ const vueImport = sfcContext.importAST.find((importNode) => t.isImportDeclaration(importNode) && importNode.source.value === '@unmagic/vue-mini');
943
953
  if (vueImport && t.isImportDeclaration(vueImport)) {
944
954
  vueImport.specifiers.push(t.importSpecifier(t.identifier(specifierName), t.identifier(specifierName)));
945
955
  }
946
956
  else {
947
- sfcContext.importAST.push(t.importDeclaration([t.importSpecifier(t.identifier(specifierName), t.identifier(specifierName))], t.stringLiteral('@vue-mini/core')));
957
+ sfcContext.importAST.push(t.importDeclaration([t.importSpecifier(t.identifier(specifierName), t.identifier(specifierName))], t.stringLiteral('@unmagic/vue-mini')));
948
958
  }
949
959
  }
950
960
  async function extractSetupBodyUsingAST(scriptContent, returnValue, bridgedFunctions, internalVars, renderVars, needsProxyRefs, isPage, scriptScope) {
@@ -1263,7 +1273,7 @@ async function parseScript(descriptor, returnValue, bridgedFunctions = new Set()
1263
1273
  const { sfcContext, setupFunAst } = await extractSetupBodyUsingAST(script, returnValue, bridgedFunctions, internalVars, renderVars, needsProxyRefs, isPage, scriptScope);
1264
1274
  // 生成import抽象语法
1265
1275
  const programBody = [
1266
- t.importDeclaration([t.importSpecifier(t.identifier('defineComponent'), t.identifier('defineComponent'))], t.stringLiteral('@vue-mini/core')),
1276
+ t.importDeclaration([t.importSpecifier(t.identifier('defineComponent'), t.identifier('defineComponent'))], t.stringLiteral('@unmagic/vue-mini')),
1267
1277
  ...sfcContext.importAST,
1268
1278
  ];
1269
1279
  // 生成defineComponent参数
@@ -1333,37 +1343,38 @@ async function parseScript(descriptor, returnValue, bridgedFunctions = new Set()
1333
1343
  /**
1334
1344
  * 替换函数中的 props 变量访问
1335
1345
  * 将 __vmsProxyRefs.propName 替换为 __vmsProps.propName
1346
+ * 使用 Babel VISITOR_KEYS 进行正确的 AST 遍历,
1347
+ * 只访问有意义的子节点,避免遍历 Babel 内部属性。
1336
1348
  */
1337
1349
  function replacePropsAccessInFunction(func, propsVarNames, propsVarName) {
1338
- // 递归遍历函数体中的所有 MemberExpression
1350
+ // 使用 Babel VISITOR_KEYS 遍历,只处理有意义的子节点
1339
1351
  function traverseNode(node) {
1340
- if (!node)
1352
+ if (!node || typeof node !== 'object')
1341
1353
  return;
1342
- // 检查当前节点是否是 MemberExpression
1354
+ // 处理 MemberExpression:检查并替换 __vmsProxyRefs.propName
1343
1355
  if (t.isMemberExpression(node)) {
1344
- // 检查是否是 __vmsProxyRefs.propName 形式
1345
1356
  if (t.isIdentifier(node.object, { name: '__vmsProxyRefs' }) &&
1346
1357
  t.isIdentifier(node.property) &&
1347
1358
  propsVarNames.has(node.property.name)) {
1348
- // 替换为 __vmsProps.propName
1349
1359
  node.object = t.identifier(propsVarName);
1350
1360
  }
1351
1361
  }
1352
- // 递归遍历子节点
1353
- if (typeof node === 'object') {
1354
- for (const key in node) {
1355
- const value = node[key];
1356
- if (Array.isArray(value)) {
1357
- value.forEach((item) => {
1358
- if (typeof item === 'object' && item !== null) {
1359
- traverseNode(item);
1360
- }
1361
- });
1362
- }
1363
- else if (typeof value === 'object' && value !== null && value.type) {
1364
- traverseNode(value);
1362
+ // 使用 VISITOR_KEYS 获取该节点类型的有效子节点属性名
1363
+ const visitorKeys = t.VISITOR_KEYS[node.type];
1364
+ if (!visitorKeys)
1365
+ return;
1366
+ for (const key of visitorKeys) {
1367
+ const value = node[key];
1368
+ if (Array.isArray(value)) {
1369
+ for (const child of value) {
1370
+ if (child && typeof child === 'object' && Object.hasOwn(child, 'type')) {
1371
+ traverseNode(child);
1372
+ }
1365
1373
  }
1366
1374
  }
1375
+ else if (value && typeof value === 'object' && Object.hasOwn(value, 'type')) {
1376
+ traverseNode(value);
1377
+ }
1367
1378
  }
1368
1379
  }
1369
1380
  traverseNode(func);
@@ -3432,262 +3443,161 @@ function processArrowFunctionExpression(ast, counter, callExpressionWithArgs, ex
3432
3443
  const wrappedBody = t__default.blockStatement([t__default.expressionStatement(body)]);
3433
3444
  return processInlineArrowFunction(wrappedBody, arrowFunctionArguments, counter, callExpressionWithArgs, excludeBindingVars, node, returnValue, ctx, isAsync);
3434
3445
  }
3435
- else if (t__default.isConditionalExpression(body)) {
3446
+ else if (t__default.isConditionalExpression(body) || t__default.isLogicalExpression(body)) {
3436
3447
  // 处理三元表达式:(e) => flag ? a() : b()
3437
- // 收集条件表达式中使用的外部变量
3448
+ // 处理逻辑表达式:(e) => flag && onClick(e)
3438
3449
  const vForInfoList = getVForInfoList(ctx, node);
3439
3450
  const vForVars = getVForVariables(ctx, node);
3440
- const arrowFunctionArgumentNames = arrowFunctionArguments.length > 0
3441
- ? new Set(arrowFunctionArguments
3442
- .map((p) => (t__default.isIdentifier(p) ? p.name : ''))
3443
- .filter(Boolean))
3444
- : undefined;
3445
- // 收集 test、consequent、alternate 中的外部变量
3446
- const varsToCollect = new Set();
3447
- const collectVarsFromNode = (node) => {
3448
- if (t__default.isIdentifier(node)) {
3449
- const name = node.name;
3450
- if (name !== EVENT_PARAM_NAME &&
3451
- name !== '$event' &&
3452
- !GLOBAL_WHITELIST.has(name) &&
3453
- !(arrowFunctionArgumentNames && arrowFunctionArgumentNames.has(name)) &&
3454
- !vForVars.has(name)) {
3455
- varsToCollect.add(name);
3456
- }
3457
- }
3458
- else if (t__default.isMemberExpression(node)) {
3459
- collectVarsFromNode(node.object);
3460
- }
3461
- else if (t__default.isCallExpression(node)) {
3462
- collectVarsFromNode(node.callee);
3463
- node.arguments.forEach((arg) => collectVarsFromNode(arg));
3464
- }
3465
- else if (t__default.isConditionalExpression(node)) {
3466
- collectVarsFromNode(node.test);
3467
- collectVarsFromNode(node.consequent);
3468
- collectVarsFromNode(node.alternate);
3469
- }
3470
- else if (t__default.isLogicalExpression(node) || t__default.isBinaryExpression(node)) {
3471
- collectVarsFromNode(node.left);
3472
- collectVarsFromNode(node.right);
3473
- }
3474
- else if (t__default.isUnaryExpression(node)) {
3475
- collectVarsFromNode(node.argument);
3451
+ return createShortExprHandler(body, arrowFunctionArguments, callExpressionWithArgs, vForInfoList, vForVars, ctx, counter, returnValue, isAsync);
3452
+ }
3453
+ return '';
3454
+ }
3455
+ function collectExternalVarsFromExpression(body, arrowFunctionArgumentNames, vForVars) {
3456
+ const varsToCollect = new Set();
3457
+ const collectVarsFromNode = (node) => {
3458
+ if (t__default.isIdentifier(node)) {
3459
+ const name = node.name;
3460
+ if (name !== EVENT_PARAM_NAME &&
3461
+ name !== '$event' &&
3462
+ !GLOBAL_WHITELIST.has(name) &&
3463
+ !(arrowFunctionArgumentNames && arrowFunctionArgumentNames.has(name)) &&
3464
+ !vForVars.has(name)) {
3465
+ varsToCollect.add(name);
3476
3466
  }
3477
- };
3467
+ }
3468
+ else if (t__default.isMemberExpression(node)) {
3469
+ collectVarsFromNode(node.object);
3470
+ }
3471
+ else if (t__default.isCallExpression(node)) {
3472
+ collectVarsFromNode(node.callee);
3473
+ node.arguments.forEach((arg) => collectVarsFromNode(arg));
3474
+ }
3475
+ else if (t__default.isConditionalExpression(node)) {
3476
+ collectVarsFromNode(node.test);
3477
+ collectVarsFromNode(node.consequent);
3478
+ collectVarsFromNode(node.alternate);
3479
+ }
3480
+ else if (t__default.isLogicalExpression(node) || t__default.isBinaryExpression(node)) {
3481
+ collectVarsFromNode(node.left);
3482
+ collectVarsFromNode(node.right);
3483
+ }
3484
+ else if (t__default.isUnaryExpression(node)) {
3485
+ collectVarsFromNode(node.argument);
3486
+ }
3487
+ };
3488
+ // 收集对应表达式类型的节点
3489
+ if (t__default.isConditionalExpression(body)) {
3478
3490
  collectVarsFromNode(body.test);
3479
3491
  collectVarsFromNode(body.consequent);
3480
3492
  collectVarsFromNode(body.alternate);
3481
- // 将收集的变量添加到 returnValue
3482
- varsToCollect.forEach((varName) => {
3483
- if (!shouldSkipVariable(varName, ctx.scriptScope)) {
3484
- addProperty(returnValue, varName);
3485
- ctx.internalVars.add(varName);
3486
- }
3487
- });
3488
- // 标记需要 __vmsProxyRefs
3489
- if (varsToCollect.size > 0) {
3490
- ctx.needsProxyRefs = true;
3491
- }
3492
- // 生成桥接函数
3493
- const functionName = counter.generateFunctionPropertyName();
3494
- const dataKey = vForInfoList && vForInfoList.length > 0
3495
- ? getFunctionIndexChar(counter.nodeDataKeyIndex++)
3496
- : '';
3497
- // 处理参数
3498
- const statements = [];
3499
- if (arrowFunctionArguments.length > 0) {
3500
- const param = arrowFunctionArguments[0];
3501
- if (t__default.isIdentifier(param) && param.name !== '$event' && param.name !== EVENT_PARAM_NAME) {
3502
- statements.push(t__default.variableDeclaration('const', [
3503
- t__default.variableDeclarator(param, t__default.memberExpression(t__default.identifier(EVENT_PARAM_NAME), t__default.identifier('detail'))),
3504
- ]));
3505
- }
3506
- }
3507
- // 处理 v-for dataset 获取
3508
- if (vForInfoList && vForInfoList.length > 0) {
3509
- const indices = vForInfoList.map((info) => getVForIndexName(info) || 'index');
3510
- const indexVars = indices.map((idx) => t__default.identifier(idx));
3511
- statements.push(t__default.variableDeclaration('const', [
3512
- t__default.variableDeclarator(t__default.objectPattern([
3513
- t__default.objectProperty(t__default.identifier(dataKey), t__default.arrayPattern(indexVars), false, false),
3514
- ]), t__default.memberExpression(t__default.memberExpression(t__default.identifier(EVENT_PARAM_NAME), t__default.identifier('currentTarget')), t__default.identifier('dataset'))),
3515
- ]));
3516
- }
3517
- // 构建处理后的条件表达式
3518
- const processConditionalExpr = (expr) => {
3519
- if (t__default.isIdentifier(expr)) {
3520
- const name = expr.name;
3521
- if (arrowFunctionArgumentNames && arrowFunctionArgumentNames.has(name)) {
3522
- return t__default.memberExpression(t__default.identifier(EVENT_PARAM_NAME), t__default.identifier('detail'));
3523
- }
3524
- if (ctx.scriptScope?.props.has(name)) {
3525
- const propsVarName = ctx.scriptScope.propsVarName || '__vmsProps';
3526
- return t__default.memberExpression(t__default.identifier(propsVarName), t__default.identifier(name));
3527
- }
3528
- if (varsToCollect.has(name)) {
3529
- return t__default.memberExpression(t__default.identifier('__vmsProxyRefs'), t__default.identifier(name));
3530
- }
3531
- return expr;
3532
- }
3533
- else if (t__default.isMemberExpression(expr)) {
3534
- return t__default.memberExpression(processConditionalExpr(expr.object), expr.property, expr.computed);
3535
- }
3536
- else if (t__default.isCallExpression(expr)) {
3537
- return t__default.callExpression(processConditionalExpr(expr.callee), expr.arguments.map((arg) => processConditionalExpr(arg)));
3538
- }
3539
- else if (t__default.isConditionalExpression(expr)) {
3540
- return t__default.conditionalExpression(processConditionalExpr(expr.test), processConditionalExpr(expr.consequent), processConditionalExpr(expr.alternate));
3541
- }
3542
- else if (t__default.isLogicalExpression(expr)) {
3543
- return t__default.logicalExpression(expr.operator, processConditionalExpr(expr.left), processConditionalExpr(expr.right));
3544
- }
3545
- else if (t__default.isBinaryExpression(expr)) {
3546
- return t__default.binaryExpression(expr.operator, processConditionalExpr(expr.left), processConditionalExpr(expr.right));
3547
- }
3548
- else if (t__default.isUnaryExpression(expr)) {
3549
- return t__default.unaryExpression(expr.operator, processConditionalExpr(expr.argument));
3550
- }
3551
- return expr;
3552
- };
3553
- const processedBody = processConditionalExpr(body);
3554
- statements.push(t__default.returnStatement(processedBody));
3555
- const functionBody = t__default.blockStatement(statements);
3556
- const dataArgsAst = vForInfoList && vForInfoList.length > 0
3557
- ? vForInfoList.map((info) => t__default.identifier(getVForIndexName(info) || 'index'))
3558
- : null;
3559
- callExpressionWithArgs.set(functionName, {
3560
- dataKey,
3561
- dataArgsAst,
3562
- returnValueBodyAst: functionBody,
3563
- isAsync,
3564
- });
3565
- return functionName;
3566
3493
  }
3567
- else if (t__default.isLogicalExpression(body)) {
3568
- // 处理逻辑表达式:(e) => flag && onClick(e)
3569
- // 复用条件表达式的处理逻辑,将逻辑表达式包装为类似条件表达式的处理
3570
- const vForInfoList = getVForInfoList(ctx, node);
3571
- const vForVars = getVForVariables(ctx, node);
3572
- const arrowFunctionArgumentNames = arrowFunctionArguments.length > 0
3573
- ? new Set(arrowFunctionArguments
3574
- .map((p) => (t__default.isIdentifier(p) ? p.name : ''))
3575
- .filter(Boolean))
3576
- : undefined;
3577
- // 收集逻辑表达式中使用的外部变量
3578
- const varsToCollect = new Set();
3579
- const collectVarsFromNode = (node) => {
3580
- if (t__default.isIdentifier(node)) {
3581
- const name = node.name;
3582
- if (name !== EVENT_PARAM_NAME &&
3583
- name !== '$event' &&
3584
- !GLOBAL_WHITELIST.has(name) &&
3585
- !(arrowFunctionArgumentNames && arrowFunctionArgumentNames.has(name)) &&
3586
- !vForVars.has(name)) {
3587
- varsToCollect.add(name);
3588
- }
3589
- }
3590
- else if (t__default.isMemberExpression(node)) {
3591
- collectVarsFromNode(node.object);
3592
- }
3593
- else if (t__default.isCallExpression(node)) {
3594
- collectVarsFromNode(node.callee);
3595
- node.arguments.forEach((arg) => collectVarsFromNode(arg));
3596
- }
3597
- else if (t__default.isLogicalExpression(node) || t__default.isBinaryExpression(node)) {
3598
- collectVarsFromNode(node.left);
3599
- collectVarsFromNode(node.right);
3600
- }
3601
- else if (t__default.isUnaryExpression(node)) {
3602
- collectVarsFromNode(node.argument);
3603
- }
3604
- };
3494
+ else {
3495
+ // LogicalExpression
3605
3496
  collectVarsFromNode(body.left);
3606
3497
  collectVarsFromNode(body.right);
3607
- // 将收集的变量添加到 returnValue
3608
- varsToCollect.forEach((varName) => {
3609
- if (!shouldSkipVariable(varName, ctx.scriptScope)) {
3610
- addProperty(returnValue, varName);
3611
- ctx.internalVars.add(varName);
3498
+ }
3499
+ return varsToCollect;
3500
+ }
3501
+ /**
3502
+ * 重写表达式中的变量引用
3503
+ * 将外部变量、props、箭头函数参数替换为正确的访问路径
3504
+ */
3505
+ function rewriteExpressionVars(expr, varsToCollect, arrowFunctionArgumentNames, ctx) {
3506
+ const processExpr = (node) => {
3507
+ if (t__default.isIdentifier(node)) {
3508
+ const name = node.name;
3509
+ if (arrowFunctionArgumentNames && arrowFunctionArgumentNames.has(name)) {
3510
+ return t__default.memberExpression(t__default.identifier(EVENT_PARAM_NAME), t__default.identifier('detail'));
3612
3511
  }
3613
- });
3614
- // 标记需要 __vmsProxyRefs
3615
- if (varsToCollect.size > 0) {
3616
- ctx.needsProxyRefs = true;
3617
- }
3618
- // 生成桥接函数
3619
- const functionName = counter.generateFunctionPropertyName();
3620
- const dataKey = vForInfoList && vForInfoList.length > 0
3621
- ? getFunctionIndexChar(counter.nodeDataKeyIndex++)
3622
- : '';
3623
- // 处理参数
3624
- const statements = [];
3625
- if (arrowFunctionArguments.length > 0) {
3626
- const param = arrowFunctionArguments[0];
3627
- if (t__default.isIdentifier(param) && param.name !== '$event' && param.name !== EVENT_PARAM_NAME) {
3628
- statements.push(t__default.variableDeclaration('const', [
3629
- t__default.variableDeclarator(param, t__default.memberExpression(t__default.identifier(EVENT_PARAM_NAME), t__default.identifier('detail'))),
3630
- ]));
3512
+ if (ctx.scriptScope?.props.has(name)) {
3513
+ const propsVarName = ctx.scriptScope.propsVarName || '__vmsProps';
3514
+ return t__default.memberExpression(t__default.identifier(propsVarName), t__default.identifier(name));
3631
3515
  }
3516
+ if (varsToCollect.has(name)) {
3517
+ return t__default.memberExpression(t__default.identifier('__vmsProxyRefs'), t__default.identifier(name));
3518
+ }
3519
+ return node;
3632
3520
  }
3633
- // 处理 v-for dataset 获取
3634
- if (vForInfoList && vForInfoList.length > 0) {
3635
- const indices = vForInfoList.map((info) => getVForIndexName(info) || 'index');
3636
- const indexVars = indices.map((idx) => t__default.identifier(idx));
3521
+ else if (t__default.isMemberExpression(node)) {
3522
+ return t__default.memberExpression(processExpr(node.object), node.property, node.computed);
3523
+ }
3524
+ else if (t__default.isCallExpression(node)) {
3525
+ return t__default.callExpression(processExpr(node.callee), node.arguments.map((arg) => processExpr(arg)));
3526
+ }
3527
+ else if (t__default.isConditionalExpression(node)) {
3528
+ return t__default.conditionalExpression(processExpr(node.test), processExpr(node.consequent), processExpr(node.alternate));
3529
+ }
3530
+ else if (t__default.isLogicalExpression(node)) {
3531
+ return t__default.logicalExpression(node.operator, processExpr(node.left), processExpr(node.right));
3532
+ }
3533
+ else if (t__default.isBinaryExpression(node)) {
3534
+ return t__default.binaryExpression(node.operator, processExpr(node.left), processExpr(node.right));
3535
+ }
3536
+ else if (t__default.isUnaryExpression(node)) {
3537
+ return t__default.unaryExpression(node.operator, processExpr(node.argument));
3538
+ }
3539
+ return node;
3540
+ };
3541
+ return processExpr(expr);
3542
+ }
3543
+ /**
3544
+ * 创建简短表达式(条件/逻辑表达式)的箭头函数处理器
3545
+ * 供 processArrowFunctionExpression 中条件表达式和逻辑表达式分支复用
3546
+ */
3547
+ function createShortExprHandler(body, arrowFunctionArguments, callExpressionWithArgs, vForInfoList, vForVars, ctx, counter, returnValue, isAsync) {
3548
+ const arrowFunctionArgumentNames = arrowFunctionArguments.length > 0
3549
+ ? new Set(arrowFunctionArguments.map((p) => (t__default.isIdentifier(p) ? p.name : '')).filter(Boolean))
3550
+ : undefined;
3551
+ // 收集外部变量
3552
+ const varsToCollect = collectExternalVarsFromExpression(body, arrowFunctionArgumentNames, vForVars);
3553
+ // 将收集的变量添加到 returnValue
3554
+ varsToCollect.forEach((varName) => {
3555
+ if (!shouldSkipVariable(varName, ctx.scriptScope)) {
3556
+ addProperty(returnValue, varName);
3557
+ ctx.internalVars.add(varName);
3558
+ }
3559
+ });
3560
+ // 标记需要 __vmsProxyRefs
3561
+ if (varsToCollect.size > 0) {
3562
+ ctx.needsProxyRefs = true;
3563
+ }
3564
+ // 生成桥接函数
3565
+ const functionName = counter.generateFunctionPropertyName();
3566
+ const dataKey = vForInfoList && vForInfoList.length > 0 ? getFunctionIndexChar(counter.nodeDataKeyIndex++) : '';
3567
+ // 处理参数
3568
+ const statements = [];
3569
+ if (arrowFunctionArguments.length > 0) {
3570
+ const param = arrowFunctionArguments[0];
3571
+ if (t__default.isIdentifier(param) && param.name !== '$event' && param.name !== EVENT_PARAM_NAME) {
3637
3572
  statements.push(t__default.variableDeclaration('const', [
3638
- t__default.variableDeclarator(t__default.objectPattern([
3639
- t__default.objectProperty(t__default.identifier(dataKey), t__default.arrayPattern(indexVars), false, false),
3640
- ]), t__default.memberExpression(t__default.memberExpression(t__default.identifier(EVENT_PARAM_NAME), t__default.identifier('currentTarget')), t__default.identifier('dataset'))),
3573
+ t__default.variableDeclarator(param, t__default.memberExpression(t__default.identifier(EVENT_PARAM_NAME), t__default.identifier('detail'))),
3641
3574
  ]));
3642
3575
  }
3643
- // 构建处理后的逻辑表达式
3644
- const processLogicalExpr = (expr) => {
3645
- if (t__default.isIdentifier(expr)) {
3646
- const name = expr.name;
3647
- if (arrowFunctionArgumentNames && arrowFunctionArgumentNames.has(name)) {
3648
- return t__default.memberExpression(t__default.identifier(EVENT_PARAM_NAME), t__default.identifier('detail'));
3649
- }
3650
- if (ctx.scriptScope?.props.has(name)) {
3651
- const propsVarName = ctx.scriptScope.propsVarName || '__vmsProps';
3652
- return t__default.memberExpression(t__default.identifier(propsVarName), t__default.identifier(name));
3653
- }
3654
- if (varsToCollect.has(name)) {
3655
- return t__default.memberExpression(t__default.identifier('__vmsProxyRefs'), t__default.identifier(name));
3656
- }
3657
- return expr;
3658
- }
3659
- else if (t__default.isMemberExpression(expr)) {
3660
- return t__default.memberExpression(processLogicalExpr(expr.object), expr.property, expr.computed);
3661
- }
3662
- else if (t__default.isCallExpression(expr)) {
3663
- return t__default.callExpression(processLogicalExpr(expr.callee), expr.arguments.map((arg) => processLogicalExpr(arg)));
3664
- }
3665
- else if (t__default.isLogicalExpression(expr)) {
3666
- return t__default.logicalExpression(expr.operator, processLogicalExpr(expr.left), processLogicalExpr(expr.right));
3667
- }
3668
- else if (t__default.isBinaryExpression(expr)) {
3669
- return t__default.binaryExpression(expr.operator, processLogicalExpr(expr.left), processLogicalExpr(expr.right));
3670
- }
3671
- else if (t__default.isUnaryExpression(expr)) {
3672
- return t__default.unaryExpression(expr.operator, processLogicalExpr(expr.argument));
3673
- }
3674
- return expr;
3675
- };
3676
- const processedBody = processLogicalExpr(body);
3677
- statements.push(t__default.returnStatement(processedBody));
3678
- const functionBody = t__default.blockStatement(statements);
3679
- const dataArgsAst = vForInfoList && vForInfoList.length > 0
3680
- ? vForInfoList.map((info) => t__default.identifier(getVForIndexName(info) || 'index'))
3681
- : null;
3682
- callExpressionWithArgs.set(functionName, {
3683
- dataKey,
3684
- dataArgsAst,
3685
- returnValueBodyAst: functionBody,
3686
- isAsync,
3687
- });
3688
- return functionName;
3689
3576
  }
3690
- return '';
3577
+ // 处理 v-for dataset 获取
3578
+ if (vForInfoList && vForInfoList.length > 0) {
3579
+ const indices = vForInfoList.map((info) => getVForIndexName(info) || 'index');
3580
+ const indexVars = indices.map((idx) => t__default.identifier(idx));
3581
+ statements.push(t__default.variableDeclaration('const', [
3582
+ t__default.variableDeclarator(t__default.objectPattern([
3583
+ t__default.objectProperty(t__default.identifier(dataKey), t__default.arrayPattern(indexVars), false, false),
3584
+ ]), t__default.memberExpression(t__default.memberExpression(t__default.identifier(EVENT_PARAM_NAME), t__default.identifier('currentTarget')), t__default.identifier('dataset'))),
3585
+ ]));
3586
+ }
3587
+ // 重写表达式中的变量引用
3588
+ const processedBody = rewriteExpressionVars(body, varsToCollect, arrowFunctionArgumentNames, ctx);
3589
+ statements.push(t__default.returnStatement(processedBody));
3590
+ const functionBody = t__default.blockStatement(statements);
3591
+ const dataArgsAst = vForInfoList && vForInfoList.length > 0
3592
+ ? vForInfoList.map((info) => t__default.identifier(getVForIndexName(info) || 'index'))
3593
+ : null;
3594
+ callExpressionWithArgs.set(functionName, {
3595
+ dataKey,
3596
+ dataArgsAst,
3597
+ returnValueBodyAst: functionBody,
3598
+ isAsync,
3599
+ });
3600
+ return functionName;
3691
3601
  }
3692
3602
  /**
3693
3603
  * 处理事件名转换
@@ -4589,7 +4499,7 @@ function createResult(key, content, priority) {
4589
4499
  * 从 v-for 指令中提取 forItem 和 forIndex
4590
4500
  * 公共逻辑,供 transformVForProp 共用
4591
4501
  */
4592
- function parseForVariables(prop) {
4502
+ function parseForVariables(prop, counter) {
4593
4503
  const directive = prop;
4594
4504
  if (!directive.forParseResult) {
4595
4505
  return undefined;
@@ -4598,15 +4508,9 @@ function parseForVariables(prop) {
4598
4508
  ? directive.forParseResult.value.content
4599
4509
  : 'item';
4600
4510
  const hasExplicitIndex = directive.forParseResult.key?.type === NodeTypes.SIMPLE_EXPRESSION;
4601
- const sourceContent = directive.forParseResult.source?.type === NodeTypes.SIMPLE_EXPRESSION
4602
- ? directive.forParseResult.source.content
4603
- : 'item';
4604
4511
  const forIndex = hasExplicitIndex
4605
4512
  ? directive.forParseResult.key.content
4606
- : `_${sourceContent
4607
- .split('.')
4608
- .pop()
4609
- ?.replace(/[^a-zA-Z0-9_]/g, '_') || 'item'}_index`;
4513
+ : counter.generateVForIndexName(forItem);
4610
4514
  return { forItem, forIndex };
4611
4515
  }
4612
4516
  /**
@@ -4623,7 +4527,7 @@ function transformVForProp(prop, context) {
4623
4527
  }
4624
4528
  // 获取数组表达式
4625
4529
  const { content: arrayName } = getTemplateNodeProp(context.node, { loc: directive.loc, exp: directive.forParseResult.source }, context.returnValue, context.counter, context.wxsExpressionStatements, context.ctx);
4626
- const forVars = parseForVariables(prop);
4530
+ const forVars = parseForVariables(prop, context.counter);
4627
4531
  if (!forVars)
4628
4532
  return undefined;
4629
4533
  // 写回 forParseResult 供后续使用
@@ -4793,12 +4697,16 @@ function parseTemplate(templateAST, filePath, isPage = false, scriptScope) {
4793
4697
  wxsFunctionCounter: 0,
4794
4698
  functionPropertyCounter: 0,
4795
4699
  nodeDataKeyIndex: 0,
4700
+ vForIndexCounter: 0,
4796
4701
  generateWxsFunctionName() {
4797
4702
  return `__wxs_${this.wxsFunctionCounter++}`;
4798
4703
  },
4799
4704
  generateFunctionPropertyName() {
4800
4705
  return `__fun_${this.functionPropertyCounter++}`;
4801
4706
  },
4707
+ generateVForIndexName(forItem) {
4708
+ return `_${forItem}_${this.vForIndexCounter++}_index`;
4709
+ },
4802
4710
  };
4803
4711
  const wxsExpressionStatements = [];
4804
4712
  const returnValue = t.objectExpression([]);
@@ -5094,7 +5002,7 @@ function generateUsingComponents(imports, thirdPartyComponents) {
5094
5002
  });
5095
5003
  return usingComponents;
5096
5004
  }
5097
- async function transformVueToMiniProgram(filePath, outputDir, isPage = false, cb, baseDir) {
5005
+ async function transformVueToMiniProgram(filePath, outputDir, isPage = false, cb) {
5098
5006
  const vueContent = readFileSync(filePath, 'utf-8');
5099
5007
  const { descriptor } = parse$1(vueContent, {
5100
5008
  filename: filePath,
@@ -5117,7 +5025,7 @@ async function transformVueToMiniProgram(filePath, outputDir, isPage = false, cb
5117
5025
  // 4. 转换 styles
5118
5026
  const css = parseStyles(styles);
5119
5027
  // 5. 生成文件夹
5120
- const componentDir = join(outputDir, relative(baseDir ?? srcDir, dirname(filePath)));
5028
+ const componentDir = join(outputDir, relative(srcDir, dirname(filePath)));
5121
5029
  if (!existsSync(componentDir)) {
5122
5030
  await mkdir(componentDir, { recursive: true });
5123
5031
  }
@@ -5205,4 +5113,672 @@ async function writeFileIfChangedAsync(filePath, newContent) {
5205
5113
  }
5206
5114
  }
5207
5115
 
5208
- export { OUTPUT_DIR as O, copyProjectConfigFile as a, config as b, copyPolyfillFiles as c, traverse$1 as d, getErrorMessage as g, handleCompileError as h, transformVueToMiniProgram as t, userConfig as u };
5116
+ const NODE_ENV = process$1.env.NODE_ENV || 'production';
5117
+ // 存储页面路径列表,用于判断组件是否为页面组件
5118
+ let pagePaths = null;
5119
+ // 缓存文件路径到是否为页面组件的映射
5120
+ const pageComponentCache = new Map();
5121
+ /**
5122
+ * 清空所有缓存(在 app.json 变更时调用)
5123
+ */
5124
+ function clearAllCaches() {
5125
+ pagePaths = null;
5126
+ pageComponentCache.clear();
5127
+ pathCache.clear();
5128
+ }
5129
+ /**
5130
+ * 读取 app.json 并生成页面路径列表
5131
+ * 页面路径格式: pages/index/Index 或 subHome/pages/home/HomeIndex
5132
+ */
5133
+ async function loadPagePaths() {
5134
+ if (pagePaths)
5135
+ return pagePaths;
5136
+ const appJsonPath = path.join(sourceDir, 'app.json');
5137
+ pagePaths = new Set();
5138
+ try {
5139
+ const appJson = await fs.readJson(appJsonPath);
5140
+ // 处理主包 pages
5141
+ if (appJson.pages) {
5142
+ for (const page of appJson.pages) {
5143
+ // page 格式: pages/index/Index
5144
+ pagePaths.add(page);
5145
+ }
5146
+ }
5147
+ // 处理分包 subPackages
5148
+ if (appJson.subPackages) {
5149
+ for (const pkg of appJson.subPackages) {
5150
+ const root = pkg.root;
5151
+ for (const page of pkg.pages) {
5152
+ // 分包页面格式: subHome/pages/home/HomeIndex
5153
+ pagePaths.add(`${root}/${page}`);
5154
+ }
5155
+ }
5156
+ }
5157
+ console.log(bold(green(`加载到 ${pagePaths.size} 个页面路径`)));
5158
+ }
5159
+ catch (error) {
5160
+ console.warn('读取 app.json 失败:', getErrorMessage(error));
5161
+ }
5162
+ return pagePaths;
5163
+ }
5164
+ /**
5165
+ * 判断文件路径是否为页面组件
5166
+ * @param filePath 文件路径,如 src/pages/index/Index.vue
5167
+ * @returns 是否为页面组件
5168
+ */
5169
+ function isPageComponent(filePath) {
5170
+ // 检查缓存
5171
+ const cached = pageComponentCache.get(filePath);
5172
+ if (typeof cached === 'boolean')
5173
+ return cached;
5174
+ if (!pagePaths || pagePaths.size === 0) {
5175
+ pageComponentCache.set(filePath, false);
5176
+ return false;
5177
+ }
5178
+ // 移除 sourceDir 前缀和 .vue 后缀
5179
+ const normalizedPath = path.relative(sourceDir, filePath).replace(/\.vue$/, '');
5180
+ const isPage = pagePaths.has(normalizedPath);
5181
+ pageComponentCache.set(filePath, isPage);
5182
+ return isPage;
5183
+ }
5184
+ // 使用用户配置或默认值
5185
+ const sourceDir = userConfig.sourceDir;
5186
+ // copyOnly 模式:跳过 Babel、直接复制的文件匹配规则
5187
+ const copyOnlyPatterns = userConfig.copyOnly ?? [];
5188
+ // 判断文件是否应跳过 Babel 编译直接复制
5189
+ function isCopyOnly(filePath) {
5190
+ // .min.js 是已压缩的第三方文件,无需 Babel 编译
5191
+ if (filePath.endsWith('.min.js'))
5192
+ return true;
5193
+ // .d.ts 类型声明文件不需要输出,直接跳过
5194
+ // (在 cb 中单独处理为 skip)
5195
+ // 用户自定义的 copyOnly 规则
5196
+ return copyOnlyPatterns.some((pattern) => filePath.includes(pattern));
5197
+ }
5198
+ // 获取 @/ 路径替换配置
5199
+ const aliasPath = userConfig.alias?.['@'] || `./${sourceDir}`;
5200
+ // 更新 babel 配置中的别名
5201
+ if (config.plugins) {
5202
+ const moduleResolverPlugin = config.plugins.find((plugin) => Array.isArray(plugin) && plugin[0] === 'module-resolver');
5203
+ if (moduleResolverPlugin &&
5204
+ Array.isArray(moduleResolverPlugin) &&
5205
+ moduleResolverPlugin[1] &&
5206
+ typeof moduleResolverPlugin[1] === 'object') {
5207
+ const options = moduleResolverPlugin[1];
5208
+ if (options.alias) {
5209
+ options.alias['@'] = aliasPath;
5210
+ }
5211
+ }
5212
+ }
5213
+ let topLevelJobs = [];
5214
+ let bundleJobs = [];
5215
+ const startTime = Date.now();
5216
+ let __PROD__ = false;
5217
+ const terserOptions = {
5218
+ ecma: 2016,
5219
+ toplevel: true,
5220
+ safari10: true,
5221
+ format: { comments: false },
5222
+ };
5223
+ let independentPackages = [];
5224
+ // 文件忽略规则 - 提取为常量避免重复定义
5225
+ const IGNORED_FILES = (file, stats) => {
5226
+ if (!stats?.isFile())
5227
+ return false;
5228
+ return (file.endsWith('.gitkeep') ||
5229
+ file.endsWith('.DS_Store') ||
5230
+ file.endsWith('.d.ts') || // 类型声明文件不需要处理
5231
+ file.includes('node_modules') ||
5232
+ file.includes('.git'));
5233
+ };
5234
+ // 并行处理配置
5235
+ const CONCURRENT_LIMIT = 5; // 同时处理的文件数量限制
5236
+ // 开发模式使用更高并发(默认 5,可根据 CPU 核心数调整)
5237
+ const DEV_CONCURRENT_LIMIT = 5;
5238
+ // 批量并行处理函数
5239
+ async function batchProcess(items, processor, concurrency = CONCURRENT_LIMIT) {
5240
+ // 将 items 分成多个批次,每批并发处理
5241
+ for (let i = 0; i < items.length; i += concurrency) {
5242
+ const batch = items.slice(i, i + concurrency);
5243
+ await Promise.all(batch.map((item) => processor(item).catch((error) => {
5244
+ console.error(`处理失败:`, error);
5245
+ })));
5246
+ }
5247
+ }
5248
+ // 路径转换缓存 - 避免重复计算
5249
+ const pathCache = new Map();
5250
+ function getOutputPath(inputPath) {
5251
+ let cached = pathCache.get(inputPath);
5252
+ if (!cached) {
5253
+ cached = inputPath.replace(sourceDir, OUTPUT_DIR);
5254
+ pathCache.set(inputPath, cached);
5255
+ }
5256
+ return cached;
5257
+ }
5258
+ // 清空路径缓存(在构建完成后调用)
5259
+ function clearPathCache() {
5260
+ pathCache.clear();
5261
+ }
5262
+ async function findIndependentPackages() {
5263
+ const appJson = await fs.readJson(path.resolve(sourceDir, 'app.json'));
5264
+ if (appJson.subpackages) {
5265
+ independentPackages = appJson.subpackages
5266
+ .filter(({ independent }) => independent)
5267
+ .map(({ root }) => root);
5268
+ }
5269
+ }
5270
+ const builtLibraries = [];
5271
+ const bundledModules = new Map();
5272
+ async function bundleModule(module, pkg) {
5273
+ const bundled = bundledModules.get(pkg);
5274
+ if (bundled?.has(module) || builtLibraries.some((library) => module.startsWith(library))) {
5275
+ return false;
5276
+ }
5277
+ if (bundled) {
5278
+ bundled.add(module);
5279
+ }
5280
+ else {
5281
+ bundledModules.set(pkg, new Set([module]));
5282
+ }
5283
+ const pkInfo = await getPackageInfo(module);
5284
+ if (pkInfo) {
5285
+ const { packageJson: { peerDependencies }, } = pkInfo;
5286
+ // 这里判断下,如果module在目标位置已存在,则直接返回true
5287
+ const targetExists = await fs.pathExists(path.resolve(pkg.replace(sourceDir, OUTPUT_DIR), 'miniprogram_npm', module));
5288
+ if (targetExists) {
5289
+ return true;
5290
+ }
5291
+ const bundle = await rollup({
5292
+ input: module,
5293
+ external: peerDependencies ? Object.keys(peerDependencies) : undefined,
5294
+ plugins: [
5295
+ commonjs(),
5296
+ replace({
5297
+ preventAssignment: true,
5298
+ values: {
5299
+ 'process.env.NODE_ENV': JSON.stringify(NODE_ENV),
5300
+ },
5301
+ }),
5302
+ resolve$1(),
5303
+ __PROD__ && terser(terserOptions),
5304
+ ].filter(Boolean),
5305
+ });
5306
+ await bundle.write({
5307
+ exports: 'named',
5308
+ file: `${pkg.replace(sourceDir, OUTPUT_DIR)}/miniprogram_npm/${module}/index.js`,
5309
+ format: 'cjs',
5310
+ });
5311
+ return true;
5312
+ }
5313
+ else {
5314
+ console.warn(`未找到 ${module} 的依赖信息`);
5315
+ return false;
5316
+ }
5317
+ }
5318
+ function traverseAST(ast, pkg, babelOnly = false) {
5319
+ traverse$1(ast, {
5320
+ CallExpression({ node }) {
5321
+ if (!t__default.isIdentifier(node.callee) ||
5322
+ node.callee.name !== 'require' ||
5323
+ !t__default.isStringLiteral(node.arguments[0]) ||
5324
+ node.arguments[0].value.startsWith('.') ||
5325
+ (babelOnly && !node.arguments[0].value.startsWith('@babel/runtime'))) {
5326
+ return;
5327
+ }
5328
+ const module = node.arguments[0].value;
5329
+ let promise = bundleModule(module, pkg);
5330
+ if (babelOnly) {
5331
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
5332
+ // @ts-expect-error
5333
+ promise = promise.then((valid) => {
5334
+ if (!valid)
5335
+ return;
5336
+ return Promise.all(independentPackages.map((item) => {
5337
+ const bundled = bundledModules.get(item);
5338
+ if (bundled) {
5339
+ bundled.add(module);
5340
+ }
5341
+ else {
5342
+ bundledModules.set(item, new Set([module]));
5343
+ }
5344
+ return fs.copy(path.join(OUTPUT_DIR, 'miniprogram_npm', module), path.join(OUTPUT_DIR, item, 'miniprogram_npm', module));
5345
+ }));
5346
+ });
5347
+ }
5348
+ bundleJobs?.push(promise);
5349
+ },
5350
+ });
5351
+ }
5352
+ async function buildComponentLibrary(name) {
5353
+ const pkInfo = await getPackageInfo(name);
5354
+ if (pkInfo) {
5355
+ const { rootPath, packageJson: { miniprogram }, } = pkInfo;
5356
+ let source = '';
5357
+ if (miniprogram) {
5358
+ source = path.join(rootPath, miniprogram);
5359
+ }
5360
+ else {
5361
+ try {
5362
+ const dist = path.join(rootPath, 'miniprogram_dist');
5363
+ const stats = await fs.stat(dist);
5364
+ if (stats.isDirectory()) {
5365
+ source = dist;
5366
+ }
5367
+ }
5368
+ catch {
5369
+ // Empty
5370
+ }
5371
+ }
5372
+ if (!source)
5373
+ return;
5374
+ const destination = path.resolve(OUTPUT_DIR, 'miniprogram_npm', name);
5375
+ builtLibraries.push(name);
5376
+ // ✅ 检查目标位置是否已存在文件夹
5377
+ const destinationExists = await fs.pathExists(destination);
5378
+ if (destinationExists) {
5379
+ return;
5380
+ }
5381
+ await fs.copy(source, destination);
5382
+ // 递归获取所有 .js 文件并处理(替代 watcher,更简洁可靠)
5383
+ const processJsFiles = async (dir) => {
5384
+ const entries = await fs.readdir(dir, { withFileTypes: true });
5385
+ const jsFiles = [];
5386
+ for (const entry of entries) {
5387
+ const fullPath = path.join(dir, entry.name);
5388
+ if (entry.isDirectory()) {
5389
+ await processJsFiles(fullPath);
5390
+ }
5391
+ else if (entry.isFile() && entry.name.endsWith('.js')) {
5392
+ jsFiles.push(fullPath);
5393
+ }
5394
+ }
5395
+ // 并行处理所有 .js 文件
5396
+ await Promise.all(jsFiles.map(async (filePath) => {
5397
+ try {
5398
+ const result = await transformFileAsync(filePath, { ast: true, ...config });
5399
+ if (result) {
5400
+ traverseAST(result.ast, sourceDir, true);
5401
+ const code = (__PROD__ ? (await minify(result.code, terserOptions)).code : result.code);
5402
+ await fs.writeFile(filePath, code);
5403
+ }
5404
+ }
5405
+ catch (error) {
5406
+ console.error(`处理 ${filePath} 失败:`, getErrorMessage(error));
5407
+ }
5408
+ }));
5409
+ };
5410
+ await processJsFiles(destination);
5411
+ // 复制到独立包
5412
+ if (independentPackages.length > 0) {
5413
+ await Promise.all(independentPackages.map(async (item) => {
5414
+ const independentDestination = path.join(OUTPUT_DIR, item, 'miniprogram_npm', name);
5415
+ const independentDestExists = await fs.pathExists(independentDestination);
5416
+ if (!independentDestExists) {
5417
+ return fs.copy(destination, independentDestination);
5418
+ }
5419
+ }));
5420
+ }
5421
+ }
5422
+ else {
5423
+ console.warn(`未找到 ${name} 的依赖信息`);
5424
+ }
5425
+ }
5426
+ async function scanDependencies() {
5427
+ try {
5428
+ const { dependencies } = await fs.readJson('package.json');
5429
+ if (dependencies) {
5430
+ // 并行处理所有依赖,提高启动速度
5431
+ const depNames = Object.keys(dependencies);
5432
+ console.log(bold(green(`扫描到 ${depNames.length} 个依赖,开始并行处理...`)));
5433
+ const startDepTime = Date.now();
5434
+ // 使用批量并行处理依赖
5435
+ await batchProcess(depNames, async (name) => {
5436
+ await buildComponentLibrary(name);
5437
+ }, 5); // 依赖构建限制为 5 个并发,避免过多资源占用
5438
+ console.log(bold(green(`依赖处理完成,耗时:${Date.now() - startDepTime}ms`)));
5439
+ }
5440
+ }
5441
+ catch (error) {
5442
+ console.warn('读取 package.json 失败:', getErrorMessage(error));
5443
+ }
5444
+ }
5445
+ // 缓存独立包路径的 normalize 结果
5446
+ const normalizedPkgPaths = new Map();
5447
+ async function dealScriptCode(filePath, result) {
5448
+ const ast = result.ast;
5449
+ let code = result.code;
5450
+ // 使用缓存避免重复 path.normalize 计算
5451
+ let pkg = independentPackages.find((item) => {
5452
+ let normalized = normalizedPkgPaths.get(item);
5453
+ if (!normalized) {
5454
+ normalized = path.normalize(`${sourceDir}/${item}`);
5455
+ normalizedPkgPaths.set(item, normalized);
5456
+ }
5457
+ return filePath.startsWith(normalized);
5458
+ });
5459
+ // The `src/` prefix is added to to distinguish `src` and `src/src`.
5460
+ traverseAST(ast, pkg ? path.join(sourceDir, pkg) : sourceDir);
5461
+ if (__PROD__) {
5462
+ code = (await minify(code, terserOptions)).code;
5463
+ }
5464
+ return code;
5465
+ }
5466
+ async function processScript(filePath) {
5467
+ try {
5468
+ const result = await transformFileAsync(path.resolve(filePath), {
5469
+ ast: true,
5470
+ ...config,
5471
+ });
5472
+ if (result) {
5473
+ const code = await dealScriptCode(filePath, result);
5474
+ const destination = path.join(getOutputPath(filePath).replace(/\.ts$/, '.js'));
5475
+ // 确保目录存在
5476
+ await fs.ensureDir(path.dirname(destination));
5477
+ // 直接写入,不需要先复制源文件
5478
+ await fs.writeFile(destination, code);
5479
+ }
5480
+ }
5481
+ catch (error) {
5482
+ // 使用统一的编译错误处理(支持 code-frame 定位)
5483
+ handleCompileError('', error, filePath);
5484
+ if (__PROD__)
5485
+ throw error;
5486
+ // 开发模式:打印后继续,不中断整个构建
5487
+ }
5488
+ }
5489
+ const cb = async (filePath, callbacks) => {
5490
+ if (filePath.endsWith('.vue')) {
5491
+ const t = performance.now();
5492
+ try {
5493
+ await transformVueToMiniProgram(filePath, OUTPUT_DIR, isPageComponent(filePath), async (generatedCode) => {
5494
+ try {
5495
+ // 先生成代码,再进行转换,这样可以更好地利用默认配置
5496
+ const result = await transformAsync(generatedCode, {
5497
+ filename: filePath.replace('.vue', '.js'),
5498
+ ...config,
5499
+ });
5500
+ if (result) {
5501
+ return dealScriptCode(filePath, result);
5502
+ }
5503
+ return `Failed to transformAsync ${filePath}`;
5504
+ }
5505
+ catch (error) {
5506
+ // 使用统一的编译错误处理(支持 code-frame 定位)
5507
+ handleCompileError('', error, filePath);
5508
+ // 返回错误占位代码,保证输出文件存在,开发模式下不中断构建
5509
+ return `console.error('Failed to compile ${filePath}: ${error.message?.replace(/'/g, "\\'")}');`;
5510
+ }
5511
+ });
5512
+ }
5513
+ catch (error) {
5514
+ // transformer.ts 内部已调用 handleCompileError 输出带 code-frame 的错误信息
5515
+ // 此处仅在生产模式下 rethrow,开发模式静默继续,不重复打印
5516
+ if (__PROD__)
5517
+ throw error;
5518
+ return;
5519
+ }
5520
+ finally {
5521
+ callbacks?.vueCb?.(performance.now() - t);
5522
+ }
5523
+ return;
5524
+ }
5525
+ // .d.ts 类型声明文件不需要输出,直接跳过
5526
+ if (filePath.endsWith('.d.ts'))
5527
+ return;
5528
+ // copyOnly 模式:跳过 Babel、直接复制(.min.js 及用户配置的 copyOnly 规则)
5529
+ if (isCopyOnly(filePath)) {
5530
+ const t = performance.now();
5531
+ const destinationPath = getOutputPath(filePath);
5532
+ await fs.ensureDir(path.dirname(destinationPath));
5533
+ await fs.copy(filePath, destinationPath);
5534
+ callbacks?.othersCb?.(performance.now() - t);
5535
+ return;
5536
+ }
5537
+ if (filePath.endsWith('.ts') || filePath.endsWith('.js')) {
5538
+ const t = performance.now();
5539
+ await processScript(filePath);
5540
+ callbacks?.jsCb?.(performance.now() - t);
5541
+ return;
5542
+ }
5543
+ const t = performance.now();
5544
+ const destinationPath = path.join(getOutputPath(filePath));
5545
+ await fs.copy(filePath, path.normalize(destinationPath));
5546
+ callbacks?.othersCb?.(performance.now() - t);
5547
+ };
5548
+ async function dev() {
5549
+ __PROD__ = false;
5550
+ const t0 = Date.now();
5551
+ // 复制polyfill文件
5552
+ copyPolyfillFiles()
5553
+ .then(() => {
5554
+ console.log(bold(green(`[timing] copyPolyfillFiles: ${Date.now() - t0}ms`)));
5555
+ return copyProjectConfigFile();
5556
+ })
5557
+ .then(() => {
5558
+ console.log(bold(green(`[timing] copyProjectConfigFile: ${Date.now() - t0}ms`)));
5559
+ return loadPagePaths();
5560
+ })
5561
+ .then(() => {
5562
+ console.log(bold(green(`[timing] loadPagePaths: ${Date.now() - t0}ms`)));
5563
+ return findIndependentPackages();
5564
+ })
5565
+ .then(() => {
5566
+ console.log(bold(green(`[timing] findIndependentPackages: ${Date.now() - t0}ms`)));
5567
+ return scanDependencies();
5568
+ })
5569
+ .then(() => {
5570
+ console.log(bold(green(`[timing] scanDependencies: ${Date.now() - t0}ms`)));
5571
+ // 用于跟踪正在处理的文件,避免重复处理
5572
+ const processingFiles = new Set();
5573
+ // 用于排队:编译期间又触发了 change 的文件
5574
+ const pendingFiles = new Set();
5575
+ // 用于收集初始扫描的文件,进行批量并行处理
5576
+ const initialFiles = [];
5577
+ let isInitialScan = true;
5578
+ chokidar
5579
+ .watch([sourceDir], {
5580
+ awaitWriteFinish: { stabilityThreshold: 100, pollInterval: 50 },
5581
+ ignored: IGNORED_FILES,
5582
+ usePolling: false,
5583
+ interval: 100,
5584
+ })
5585
+ .on('add', (filePath) => {
5586
+ if (isInitialScan) {
5587
+ // 初始扫描阶段,收集文件用于批量处理
5588
+ initialFiles.push(filePath);
5589
+ }
5590
+ else {
5591
+ // 运行时新增文件,立即处理
5592
+ const promise = cb(filePath);
5593
+ topLevelJobs?.push(promise);
5594
+ }
5595
+ })
5596
+ .on('addDir', (dirPath) => {
5597
+ // 新建目录时,在输出目录同步创建
5598
+ const outputDir = getOutputPath(dirPath);
5599
+ const promise = fs.ensureDir(outputDir);
5600
+ topLevelJobs?.push(promise);
5601
+ })
5602
+ .on('unlink', async (filePath) => {
5603
+ // 文件删除时同步删除目标文件
5604
+ const outputPath = getOutputPath(filePath);
5605
+ const basePath = outputPath.replace(/\.vue$/, '');
5606
+ const filesToDelete = filePath.endsWith('.vue')
5607
+ ? [`${basePath}.js`, `${basePath}.wxml`, `${basePath}.wxss`, `${basePath}.json`]
5608
+ : [path.join(outputPath)];
5609
+ try {
5610
+ await Promise.all(filesToDelete.map((f) => fs.remove(f)));
5611
+ // 同步移除 pathCache 中的缓存
5612
+ pathCache.delete(filePath);
5613
+ }
5614
+ catch (error) {
5615
+ console.warn(`删除目标文件失败:${filesToDelete.join(', ')}`, getErrorMessage(error));
5616
+ }
5617
+ })
5618
+ .on('unlinkDir', async (dirPath) => {
5619
+ // 目录删除时同步删除输出目录
5620
+ const outputDir = getOutputPath(dirPath);
5621
+ try {
5622
+ await fs.remove(outputDir);
5623
+ }
5624
+ catch (error) {
5625
+ console.warn(`删除目标目录失败:${outputDir}`, getErrorMessage(error));
5626
+ }
5627
+ })
5628
+ .on('change', async (filePath) => {
5629
+ // 如果 app.json 变更,清空所有缓存并重新加载页面路径
5630
+ if (filePath.endsWith('app.json')) {
5631
+ console.log(bold(green('检测到 app.json 变更,清空缓存并重新加载页面路径...')));
5632
+ clearAllCaches();
5633
+ await loadPagePaths();
5634
+ }
5635
+ // 如果文件正在处理中,标记需要重新处理(排队一次),不直接丢弃
5636
+ if (processingFiles.has(filePath)) {
5637
+ pendingFiles.add(filePath);
5638
+ return;
5639
+ }
5640
+ // 使用循环代替递归,避免调用栈过深
5641
+ const runCompile = async (initialPath) => {
5642
+ let targetPath = initialPath;
5643
+ while (targetPath) {
5644
+ processingFiles.add(targetPath);
5645
+ const date = Date.now();
5646
+ console.log(bold(green(`文件已修改:${targetPath}`)));
5647
+ let shouldContinue = false;
5648
+ try {
5649
+ await cb(targetPath);
5650
+ console.log(bold(green(`文件已处理完毕,耗时:${Date.now() - date}ms`)));
5651
+ }
5652
+ finally {
5653
+ processingFiles.delete(targetPath);
5654
+ // 如果编译期间又有新的保存,继续循环处理
5655
+ if (pendingFiles.has(targetPath)) {
5656
+ pendingFiles.delete(targetPath);
5657
+ shouldContinue = true;
5658
+ }
5659
+ }
5660
+ if (!shouldContinue) {
5661
+ break;
5662
+ }
5663
+ }
5664
+ };
5665
+ await runCompile(filePath);
5666
+ })
5667
+ .on('ready', async () => {
5668
+ // 标记初始扫描完成
5669
+ isInitialScan = false;
5670
+ console.log(bold(green(`[timing] chokidar ready(文件扫描完成): ${Date.now() - t0}ms,共 ${initialFiles.length} 个文件`)));
5671
+ // 统计文件类型
5672
+ const vueFiles = initialFiles.filter((f) => f.endsWith('.vue'));
5673
+ const tsFiles = initialFiles.filter((f) => f.endsWith('.ts') || f.endsWith('.js'));
5674
+ const otherFiles = initialFiles.filter((f) => !f.endsWith('.vue') && !f.endsWith('.ts') && !f.endsWith('.js'));
5675
+ console.log(bold(green(`[timing] 文件分布:vue=${vueFiles.length}, ts/js=${tsFiles.length}, 其他=${otherFiles.length}`)));
5676
+ // 文件处理器(带计时)
5677
+ let vueTime = 0, tsTime = 0, otherTime = 0;
5678
+ const fileProcessor = async (filePath) => {
5679
+ await cb(filePath, {
5680
+ vueCb: (elapsed) => {
5681
+ vueTime += elapsed;
5682
+ },
5683
+ jsCb: (elapsed) => {
5684
+ tsTime += elapsed;
5685
+ },
5686
+ othersCb: (elapsed) => {
5687
+ otherTime += elapsed;
5688
+ },
5689
+ });
5690
+ };
5691
+ // 使用批量并行处理初始文件(开发模式使用更高并发)
5692
+ if (initialFiles.length > 0) {
5693
+ console.log(bold(green(`开始并行处理 ${initialFiles.length} 个文件(并发=${DEV_CONCURRENT_LIMIT})...`)));
5694
+ const processStartTime = Date.now();
5695
+ await batchProcess(initialFiles, fileProcessor, DEV_CONCURRENT_LIMIT);
5696
+ console.log(bold(green(`[timing] 并行处理完成:${Date.now() - processStartTime}ms(总耗时 ${Date.now() - t0}ms)`)));
5697
+ console.log(bold(green(`[timing] 耗时分布:vue=${vueTime}ms, ts/js=${tsTime}ms, 其他=${otherTime}ms`)));
5698
+ }
5699
+ await Promise.all(bundleJobs);
5700
+ console.log(bold(green(`启动完成,耗时:${Date.now() - startTime}ms`)));
5701
+ console.log(bold(green('监听文件变化中...')));
5702
+ // Release memory.
5703
+ topLevelJobs = null;
5704
+ bundleJobs = null;
5705
+ // 开发模式下不清空缓存,保持性能优势
5706
+ });
5707
+ });
5708
+ }
5709
+ async function prod(options) {
5710
+ __PROD__ = true;
5711
+ return new Promise((resolve, reject) => {
5712
+ fs.remove(OUTPUT_DIR)
5713
+ .then(() => copyPolyfillFiles())
5714
+ .then(() => copyProjectConfigFile())
5715
+ .then(() => loadPagePaths())
5716
+ .then(() => findIndependentPackages())
5717
+ .then(() => scanDependencies())
5718
+ .then(() => {
5719
+ const initialFiles = [];
5720
+ let isInitialScan = true;
5721
+ const watcher = chokidar.watch([sourceDir], {
5722
+ ignored: IGNORED_FILES,
5723
+ });
5724
+ watcher.on('add', (filePath) => {
5725
+ if (isInitialScan) {
5726
+ initialFiles.push(filePath);
5727
+ }
5728
+ else {
5729
+ const promise = cb(filePath);
5730
+ topLevelJobs.push(promise);
5731
+ }
5732
+ });
5733
+ watcher.on('ready', async () => {
5734
+ isInitialScan = false;
5735
+ // 文件处理器
5736
+ const fileProcessor = async (filePath) => {
5737
+ await cb(filePath);
5738
+ };
5739
+ // 使用批量并行处理初始文件(生产环境使用更高的并发数)
5740
+ if (initialFiles.length > 0) {
5741
+ console.log(bold(green(`开始并行处理 ${initialFiles.length} 个文件...`)));
5742
+ const processStartTime = Date.now();
5743
+ await batchProcess(initialFiles, fileProcessor, CONCURRENT_LIMIT);
5744
+ console.log(bold(green(`并行处理完成,耗时:${Date.now() - processStartTime}ms`)));
5745
+ }
5746
+ const promise = watcher.close();
5747
+ topLevelJobs.push(promise);
5748
+ await Promise.all(topLevelJobs);
5749
+ await Promise.all(bundleJobs);
5750
+ // Release memory and clear cache.
5751
+ topLevelJobs = null;
5752
+ bundleJobs = null;
5753
+ clearPathCache();
5754
+ normalizedPkgPaths.clear();
5755
+ if (options.upload) {
5756
+ const { default: ci } = await import('miniprogram-ci');
5757
+ const project = new ci.Project({
5758
+ appid: userConfig.wx.appid,
5759
+ type: 'miniProgram',
5760
+ projectPath: OUTPUT_DIR,
5761
+ privateKeyPath: userConfig.wx.privateKeyPath,
5762
+ ignores: [],
5763
+ });
5764
+ console.log(bold(green('上传中...')));
5765
+ // 读取位于 projectPath 下的 project.config.json
5766
+ const uploadResult = await ci.upload({
5767
+ project,
5768
+ version: userConfig.wx.version,
5769
+ desc: userConfig.wx.description,
5770
+ setting: {
5771
+ useProjectConfig: true,
5772
+ },
5773
+ onProgressUpdate: void 0,
5774
+ });
5775
+ console.log(bold(green(`上传结果:`)), uploadResult, '当前编译环境:', NODE_ENV);
5776
+ }
5777
+ resolve();
5778
+ });
5779
+ })
5780
+ .catch(reject);
5781
+ });
5782
+ }
5783
+
5784
+ export { dev, prod };