@unmagic/vms 0.0.3-beta.0 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.js +1 -9
- package/dist/{transformer-DjOYWuap.js → cli-R8YB9UUi.js} +853 -277
- package/dist/index.js +2 -6
- package/dist/macro.d.ts +2 -2
- package/package.json +16 -14
- package/dist/build-package-B3ztw0_M.js +0 -86
- package/dist/cli-vfgVOW0G.js +0 -818
|
@@ -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
|
|
933
|
-
* 如果已存在则跳过,否则追加到已有的 @vue-mini
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
//
|
|
1350
|
+
// 使用 Babel VISITOR_KEYS 遍历,只处理有意义的子节点
|
|
1339
1351
|
function traverseNode(node) {
|
|
1340
|
-
if (!node)
|
|
1352
|
+
if (!node || typeof node !== 'object')
|
|
1341
1353
|
return;
|
|
1342
|
-
//
|
|
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
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
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
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
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
|
|
3568
|
-
//
|
|
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
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
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
|
-
|
|
3615
|
-
|
|
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
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
:
|
|
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
|
|
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(
|
|
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
|
-
|
|
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 };
|