UNPKG

ctc-track-plugin

Version:

uniapp 小程序埋点劫持

1 lines 8.3 kB
{"version":3,"sources":["../src/inject-click-handler.ts"],"sourcesContent":["/**\n * @description\n * @version\n * @author\n * @refer https://juejin.cn/post/7357609459345506330?earchId=20250730133928053080265BFB46DB6163\n */\n\n// inject-click-handler.ts vite插件\nimport { parse } from 'vue/compiler-sfc';\nimport { Plugin } from 'vite';\n\ninterface Replacement {\n source: string;\n replaceSource: string;\n}\n\nexport default (): Plugin => ({\n name: 'inject-click-handler',\n transform(code, id) {\n try {\n if (!/.vue$/.test(id)) return null;\n const parseCode = parse(code);\n if (!parseCode) return null;\n if (!parseCode.descriptor?.template?.content) return null;\n\n const { content } = parseCode.descriptor.template;\n\n let $code = content;\n const replacements: Replacement[] = [];\n\n // 递归遍历AST节点\n // 处理节点属性中的埋点逻辑\n const handleMdProp = (node: any, replacements: Replacement[]) => {\n const mdProp = node.props.find(\n (prop) =>\n (prop.type === 6 && prop.name === 'data-manual-track') ||\n (prop.type === 7 &&\n prop.name === 'bind' &&\n prop.arg?.content === 'data-manual-track'),\n );\n\n if (mdProp) {\n const tagName = node.tag;\n const mdContent =\n mdProp.type === 6\n ? `'${mdProp.value?.content || ''}'`\n : mdProp.exp?.content || '';\n\n const clickEvent = node.props.find(\n (prop) =>\n prop.type === 7 &&\n prop.name === 'on' &&\n prop.arg?.content === 'click',\n );\n\n const text =\n node.children.find((item) => item.type === 2)?.content ?? '';\n\n if (clickEvent) {\n const expContent = clickEvent.exp?.content || '';\n const isFunctionCall =\n /^\\s*[a-zA-Z_$][\\w$]*\\s*\\([^)]*\\)\\s*$|^\\s*[a-zA-Z_$][\\w$]*\\s*$/.test(\n expContent,\n );\n const fixedExp = isFunctionCall\n ? /\\([^)]*\\)/.test(expContent)\n ? expContent\n : `${expContent}()`\n : /\\s*[\\w-]+\\s*=\\s*.*?\\s*/.test(expContent)\n ? expContent\n : `${expContent}($event)`;\n\n const newEventString = `@click.stop=\"sendMd({\n content:${mdContent},\n tag:'${tagName}',\n text:'${text}'\n });${fixedExp}\"`;\n\n const newNodeStr = node.loc.source\n .replace(clickEvent.loc.source, newEventString)\n .trim();\n\n replacements.push({\n source: node.loc.source,\n replaceSource: newNodeStr,\n });\n } else {\n const newEventString = `@click.stop=\"sendMd({\n content:${mdContent},\n tag:${tagName},\n text:'${text}'\n })\"`;\n\n const closingBracketIndex = node.loc.source.lastIndexOf('>');\n const isSelfClosing =\n node.loc.source[closingBracketIndex - 1] === '/';\n\n const newNodeStr = isSelfClosing\n ? node.loc.source.slice(0, closingBracketIndex - 1).trim() +\n ` ${newEventString} />`\n : node.loc.source.slice(0, closingBracketIndex).trim() +\n ` ${newEventString}>`;\n\n replacements.push({\n source: node.loc.source,\n replaceSource: newNodeStr,\n });\n }\n } else if (node.tag === 'navigator' && node.type === 1) {\n const url =\n node.props.find((item) => item.name === 'url')?.value?.content ??\n node.props.find((item) => item.rawName === ':url')?.exp?.content;\n\n const newNodeStr = node.loc.source\n .replace(\n /<navigator([^>]*)>/,\n `<navigator$1 @click.stop=\"sendPageMd('${url}')\">`,\n )\n .trim();\n\n replacements.push({\n source: node.loc.source,\n replaceSource: newNodeStr,\n });\n }\n };\n\n // 递归遍历AST节点\n const traverse = (node: any, replacements: Replacement[]) => {\n if (node?.props?.length) {\n handleMdProp(node, replacements);\n }\n\n if (node.children) {\n node.children.forEach((child: any) => traverse(child, replacements));\n }\n };\n\n // 开始遍历AST\n traverse(parseCode.descriptor.template.ast, replacements);\n\n // 按节点长度倒序替换(避免嵌套节点替换问题)\n replacements\n .sort((a, b) => b.source.length - a.source.length)\n .forEach(({ source, replaceSource }) => {\n $code = $code.replace(source, replaceSource);\n });\n\n // 返回修改后的代码\n return {\n code: code.replace(content, $code),\n map: null,\n };\n } catch (e) {\n console.error(`埋点注入失败: ${e}`);\n return null;\n }\n },\n});\n"],"mappings":"4ZAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,IAAA,eAAAC,EAAAH,GAQA,IAAAI,EAAsB,4BAQfF,EAAQ,KAAe,CAC5B,KAAM,uBACN,UAAUG,EAAMC,EAAI,CAlBtB,IAAAC,EAAAC,EAmBI,GAAI,CACF,GAAI,CAAC,QAAQ,KAAKF,CAAE,EAAG,OAAO,KAC9B,IAAMG,KAAY,SAAMJ,CAAI,EAE5B,GADI,CAACI,GACD,GAACD,GAAAD,EAAAE,EAAU,aAAV,YAAAF,EAAsB,WAAtB,MAAAC,EAAgC,SAAS,OAAO,KAErD,GAAM,CAAE,QAAAE,CAAQ,EAAID,EAAU,WAAW,SAErCE,EAAQD,EACNE,EAA8B,CAAC,EAI/BC,EAAe,CAACC,EAAWF,IAAgC,CAhCvE,IAAAL,EAAAC,EAAAO,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAiCQ,IAAMC,EAASP,EAAK,MAAM,KACvBQ,GAAM,CAlCjB,IAAAf,EAmCa,OAAAe,EAAK,OAAS,GAAKA,EAAK,OAAS,qBACjCA,EAAK,OAAS,GACbA,EAAK,OAAS,UACdf,EAAAe,EAAK,MAAL,YAAAf,EAAU,WAAY,oBAC5B,EAEA,GAAIc,EAAQ,CACV,IAAME,EAAUT,EAAK,IACfU,EACJH,EAAO,OAAS,EACZ,MAAId,EAAAc,EAAO,QAAP,YAAAd,EAAc,UAAW,EAAE,MAC/BC,EAAAa,EAAO,MAAP,YAAAb,EAAY,UAAW,GAEvBiB,EAAaX,EAAK,MAAM,KAC3BQ,GAAM,CAjDnB,IAAAf,EAkDc,OAAAe,EAAK,OAAS,GACdA,EAAK,OAAS,QACdf,EAAAe,EAAK,MAAL,YAAAf,EAAU,WAAY,QAC1B,EAEMmB,IACJX,EAAAD,EAAK,SAAS,KAAMa,GAASA,EAAK,OAAS,CAAC,IAA5C,YAAAZ,EAA+C,UAAW,GAE5D,GAAIU,EAAY,CACd,IAAMG,IAAaZ,EAAAS,EAAW,MAAX,YAAAT,EAAgB,UAAW,GAKxCa,EAHJ,gEAAgE,KAC9DD,CACF,EAEE,YAAY,KAAKA,CAAU,EACzBA,EACA,GAAGA,CAAU,KACf,yBAAyB,KAAKA,CAAU,EACtCA,EACA,GAAGA,CAAU,WAEbE,EAAiB;AAAA,wBACXN,CAAS;AAAA,qBACZD,CAAO;AAAA,sBACNG,CAAI;AAAA,iBACTG,CAAQ,IAEPE,EAAajB,EAAK,IAAI,OACzB,QAAQW,EAAW,IAAI,OAAQK,CAAc,EAC7C,KAAK,EAERlB,EAAa,KAAK,CAChB,OAAQE,EAAK,IAAI,OACjB,cAAeiB,CACjB,CAAC,CACH,KAAO,CACL,IAAMD,EAAiB;AAAA,wBACXN,CAAS;AAAA,oBACbD,CAAO;AAAA,sBACLG,CAAI;AAAA,iBAGRM,EAAsBlB,EAAK,IAAI,OAAO,YAAY,GAAG,EAIrDiB,EAFJjB,EAAK,IAAI,OAAOkB,EAAsB,CAAC,IAAM,IAG3ClB,EAAK,IAAI,OAAO,MAAM,EAAGkB,EAAsB,CAAC,EAAE,KAAK,EACzD,IAAIF,CAAc,MAChBhB,EAAK,IAAI,OAAO,MAAM,EAAGkB,CAAmB,EAAE,KAAK,EACrD,IAAIF,CAAc,IAEpBlB,EAAa,KAAK,CAChB,OAAQE,EAAK,IAAI,OACjB,cAAeiB,CACjB,CAAC,CACH,CACF,SAAWjB,EAAK,MAAQ,aAAeA,EAAK,OAAS,EAAG,CACtD,IAAMmB,IACJf,GAAAD,EAAAH,EAAK,MAAM,KAAMa,GAASA,EAAK,OAAS,KAAK,IAA7C,YAAAV,EAAgD,QAAhD,YAAAC,EAAuD,YACvDE,GAAAD,EAAAL,EAAK,MAAM,KAAMa,GAASA,EAAK,UAAY,MAAM,IAAjD,YAAAR,EAAoD,MAApD,YAAAC,EAAyD,SAErDW,EAAajB,EAAK,IAAI,OACzB,QACC,qBACA,yCAAyCmB,CAAG,MAC9C,EACC,KAAK,EAERrB,EAAa,KAAK,CAChB,OAAQE,EAAK,IAAI,OACjB,cAAeiB,CACjB,CAAC,CACH,CACF,EAGMG,EAAW,CAACpB,EAAWF,IAAgC,CAhInE,IAAAL,GAiIYA,EAAAO,GAAA,YAAAA,EAAM,QAAN,MAAAP,EAAa,QACfM,EAAaC,EAAMF,CAAY,EAG7BE,EAAK,UACPA,EAAK,SAAS,QAASqB,GAAeD,EAASC,EAAOvB,CAAY,CAAC,CAEvE,EAGA,OAAAsB,EAASzB,EAAU,WAAW,SAAS,IAAKG,CAAY,EAGxDA,EACG,KAAK,CAACwB,EAAGC,IAAMA,EAAE,OAAO,OAASD,EAAE,OAAO,MAAM,EAChD,QAAQ,CAAC,CAAE,OAAAE,EAAQ,cAAAC,CAAc,IAAM,CACtC5B,EAAQA,EAAM,QAAQ2B,EAAQC,CAAa,CAC7C,CAAC,EAGI,CACL,KAAMlC,EAAK,QAAQK,EAASC,CAAK,EACjC,IAAK,IACP,CACF,OAAS6B,EAAG,CACV,eAAQ,MAAM,yCAAWA,CAAC,EAAE,EACrB,IACT,CACF,CACF","names":["inject_click_handler_exports","__export","inject_click_handler_default","__toCommonJS","import_compiler_sfc","code","id","_a","_b","parseCode","content","$code","replacements","handleMdProp","node","_c","_d","_e","_f","_g","_h","mdProp","prop","tagName","mdContent","clickEvent","text","item","expContent","fixedExp","newEventString","newNodeStr","closingBracketIndex","url","traverse","child","a","b","source","replaceSource","e"]}