feat(api-babel): 支持Taro.xx.yy形式的api treeshaking#18848
Conversation
Walkthrough此PR 将大量 package.json 的版本从 4.1.11 升级到 4.1.12-alpha.1,并在 packages/babel-plugin-transform-taroapi/src/index.ts 中新增/扩展对 Taro 命名空间(Taro.xx.yy)形式的识别与树摇重写逻辑(含对 TS cast 与可选链的处理)。 Changes
Sequence Diagram(s)(无序列图 — 变更未满足生成时需的多角色顺序交互条件) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
诗
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #18848 +/- ##
==========================================
- Coverage 56.31% 56.26% -0.05%
==========================================
Files 447 447
Lines 23352 23399 +47
Branches 5776 5800 +24
==========================================
+ Hits 13150 13165 +15
- Misses 8372 8394 +22
- Partials 1830 1840 +10
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/babel-plugin-transform-taroapi/src/index.ts (1)
134-143: 建议抽取flatName到本地标识符的复用逻辑Line [134]-Line [143] 与 Line [205]-Line [212] 的
invokedApis查找/创建逻辑完全重复。建议提取 helper,避免后续两个分支行为漂移。Also applies to: 205-212
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/babel-plugin-transform-taroapi/src/index.ts` around lines 134 - 143, The logic that builds flatName and looks up/creates an entry in invokedApis is duplicated; extract it into a small helper (e.g., getOrCreateInvokedApiIdentifier) that accepts the computed flatName (from namespaceName and methodName), the current ast scope (for generateUid), and invokedApis, then returns the generated identifier name or existing one; replace the duplicated blocks around flatName/this.apis checks (the code using flatName, invokedApis.has, ast.scope.generateUid, invokedApis.set, and t.identifier) at both locations (the block using namespaceName/methodName and the similar block at lines ~205-212) with calls to that helper to ensure single-point behavior and avoid drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/babel-plugin-transform-taroapi/src/index.ts`:
- Around line 125-150: The current transformation in the block that computes
isCalleeOfCall and then rewrites nested namespace member expressions (using
stripTSCast, invokedApis, this.apis and ast.replaceWith) lacks protection
against being the left-hand side of an assignment, so expressions like
Taro.xx.yy = fn get wrongly rewritten; add an isAssignmentLHS guard (similar to
the existing protection used for single-level Taro.xxx) by detecting when
ast.parent is an AssignmentExpression (or OptionalAssignment if applicable) and
ast.parent.left === node and skip the rewrite when true.
---
Nitpick comments:
In `@packages/babel-plugin-transform-taroapi/src/index.ts`:
- Around line 134-143: The logic that builds flatName and looks up/creates an
entry in invokedApis is duplicated; extract it into a small helper (e.g.,
getOrCreateInvokedApiIdentifier) that accepts the computed flatName (from
namespaceName and methodName), the current ast scope (for generateUid), and
invokedApis, then returns the generated identifier name or existing one; replace
the duplicated blocks around flatName/this.apis checks (the code using flatName,
invokedApis.has, ast.scope.generateUid, invokedApis.set, and t.identifier) at
both locations (the block using namespaceName/methodName and the similar block
at lines ~205-212) with calls to that helper to ensure single-point behavior and
avoid drift.
| const isCalleeOfCall = (t.isCallExpression(ast.parent) || t.isOptionalCallExpression(ast.parent)) && (ast.parent as any).callee === node | ||
| if (!isCalleeOfCall) { | ||
| const innerObj = stripTSCast(node.object) | ||
| if (t.isMemberExpression(innerObj) || t.isOptionalMemberExpression(innerObj)) { | ||
| const isTaroNamespace = t.isIdentifier(innerObj.object, { name: taroName }) | ||
| if (isTaroNamespace) { | ||
| const namespaceName = t.isIdentifier(innerObj.property) ? innerObj.property.name : (t.isStringLiteral(innerObj.property) ? innerObj.property.value : null) | ||
| const methodName = t.isIdentifier(node.property) ? node.property.name : (t.isStringLiteral(node.property) ? node.property.value : null) | ||
| if (namespaceName && methodName) { | ||
| const flatName = `${namespaceName}_${methodName}` | ||
| if (this.apis.has(flatName)) { | ||
| let identifier: BabelCore.types.Identifier | ||
| if (invokedApis.has(flatName)) { | ||
| identifier = t.identifier(invokedApis.get(flatName)!) | ||
| } else { | ||
| const newName = ast.scope.generateUid(flatName) | ||
| invokedApis.set(flatName, newName) | ||
| identifier = t.identifier(newName) | ||
| } | ||
| ast.replaceWith(identifier as any) | ||
| return | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's find and examine the target file
find . -type f -name "index.ts" -path "*/babel-plugin-transform-taroapi/src/*" | head -5Repository: NervJS/taro
Length of output: 109
🏁 Script executed:
# Read the file to see the context around lines 125-150 and 171
cat -n packages/babel-plugin-transform-taroapi/src/index.ts | sed -n '100,200p'Repository: NervJS/taro
Length of output: 5262
🏁 Script executed:
# Get the total line count to ensure we're looking at the right file
wc -l packages/babel-plugin-transform-taroapi/src/index.tsRepository: NervJS/taro
Length of output: 111
🏁 Script executed:
# Check the exact context around line 171 to understand the assignment protection pattern
cat -n packages/babel-plugin-transform-taroapi/src/index.ts | sed -n '168,185p'Repository: NervJS/taro
Length of output: 966
🏁 Script executed:
# Search for other assignment-related checks in the file
rg -n "isAssignment|AssignmentExpression" packages/babel-plugin-transform-taroapi/src/index.tsRepository: NervJS/taro
Length of output: 273
🏁 Script executed:
# Let's check what happens in the CallExpression handler to see if there's additional protection there
cat -n packages/babel-plugin-transform-taroapi/src/index.ts | sed -n '189,230p'Repository: NervJS/taro
Length of output: 2456
🏁 Script executed:
# Check if there's any parent checking for the first MemberExpression handler (lines 125-150)
cat -n packages/babel-plugin-transform-taroapi/src/index.ts | sed -n '120,155p'Repository: NervJS/taro
Length of output: 2200
缺少赋值左值保护,会产生非法重写
第 126-145 行的处理逻辑缺少对赋值表达式左值的保护。当源码为 Taro.xx.yy = fn 时,会被错误地改写为 imported_id = fn,造成语法错误或运行时异常。第 171 行已有对单层命名空间 Taro.xxx 的正确保护,应对嵌套命名空间采用一致的防护措施。
建议在第 126 行添加 isAssignmentLHS 检查,参考如下:
🔧 建议修复
'MemberExpression|OptionalMemberExpression' (ast: BabelCore.NodePath<any>) {
const node = ast.node
// 处理两层命名空间属性访问:Taro.xx.yy / Taro?.xx?.yy(非调用场景)
// 调用场景由 CallExpression|OptionalCallExpression 负责
const isCalleeOfCall = (t.isCallExpression(ast.parent) || t.isOptionalCallExpression(ast.parent)) && (ast.parent as any).callee === node
- if (!isCalleeOfCall) {
+ const isAssignmentLHS = t.isAssignmentExpression(ast.parent) && ast.parent.left === node
+ if (!isCalleeOfCall && !isAssignmentLHS) {
const innerObj = stripTSCast(node.object)
if (t.isMemberExpression(innerObj) || t.isOptionalMemberExpression(innerObj)) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/babel-plugin-transform-taroapi/src/index.ts` around lines 125 - 150,
The current transformation in the block that computes isCalleeOfCall and then
rewrites nested namespace member expressions (using stripTSCast, invokedApis,
this.apis and ast.replaceWith) lacks protection against being the left-hand side
of an assignment, so expressions like Taro.xx.yy = fn get wrongly rewritten; add
an isAssignmentLHS guard (similar to the existing protection used for
single-level Taro.xxx) by detecting when ast.parent is an AssignmentExpression
(or OptionalAssignment if applicable) and ast.parent.left === node and skip the
rewrite when true.
这个 PR 做了什么? (简要描述所做更改)
这个 PR 是什么类型? (至少选择一个)
这个 PR 涉及以下平台:
Summary by CodeRabbit
发布说明
新功能
其他更新