Browse Source

fix: 修复 EventSource extends Map 在 Taro 4.1.11 压缩后未被替换的问题

alphaH 2 weeks ago
parent
commit
b2220b4302
2 changed files with 94 additions and 105 deletions
  1. 41 63
      scripts/AlipayEventSourceFixPlugin.js
  2. 53 42
      scripts/fix-alipay-event-source.js

+ 41 - 63
scripts/AlipayEventSourceFixPlugin.js

@@ -3,7 +3,6 @@ const path = require('path');
 
 class AlipayEventSourceFixPlugin {
   apply(compiler) {
-    // 在构建完成后执行
     compiler.hooks.afterEmit.tapAsync('AlipayEventSourceFixPlugin', (compilation, callback) => {
       this.fixEventSource();
       callback();
@@ -12,57 +11,70 @@ class AlipayEventSourceFixPlugin {
 
   fixEventSource() {
     const taroJsPath = path.join(process.cwd(), 'dist', 'taro.js');
-    
+
     if (!fs.existsSync(taroJsPath)) {
       console.log('AlipayEventSourceFixPlugin: dist/taro.js not found');
       return;
     }
-    
+
     console.log('AlipayEventSourceFixPlugin: Fixing EventSource in dist/taro.js...');
-    
+
     let content = fs.readFileSync(taroJsPath, 'utf8');
-    
-    // 检查是否存在EventSource相关的代码
-    if (content.includes('EventSource')) {
+    let replaced = false;
+
+    // 新策略: Taro 4.x 压缩后的 EventSource (class X extends Map with removeNode)
+    if (content.includes('extends Map{removeNode(')) {
+      console.log('AlipayEventSourceFixPlugin: Found minified EventSource (extends Map with removeNode)');
+
+      const minifiedPattern =
+        /class \w+ extends Map\{removeNode\([\s\S]*?removeNodeTree\([\s\S]*?\}\}const r=new \w+/g;
+
+      if (minifiedPattern.test(content)) {
+        const replacement =
+          'class EventSource{data={};get(e){return this.data[e]};set(e,t){this.data[e]=t};delete(e){delete this.data[e]};has(e){return e in this.data};removeNode(e){const{sid:t,uid:n}=e;this.delete(t);n!==t&&n&&this.delete(n)};removeNodeTree(e){this.removeNode(e);const{childNodes:t}=e;t.forEach(e=>this.removeNodeTree(e))}}const r=new EventSource';
+
+        content = content.replace(minifiedPattern, replacement);
+        fs.writeFileSync(taroJsPath, content, 'utf8');
+        console.log('AlipayEventSourceFixPlugin: Success: Minified EventSource replaced');
+        replaced = true;
+      }
+    }
+
+    // 原有策略: 处理未压缩的 EventSource
+    if (!replaced && content.includes('EventSource')) {
       console.log('AlipayEventSourceFixPlugin: Found EventSource in dist/taro.js');
-      
-      // 新的EventSource实现(使用标准格式,确保语法正确)
-      const newEventSource = 'class EventSource {\n  data = {};\n\n  get(id) {\n    return this.data[id];\n  }\n\n  set(id, value) {\n    this.data[id] = value;\n  }\n\n  delete(id) {\n    delete this.data[id];\n  }\n\n  has(id) {\n    return id in this.data;\n  }\n\n  removeNode(child) {\n    const { sid, uid } = child;\n    this.delete(sid);\n    if (uid !== sid && uid) this.delete(uid);\n  }\n\n  removeNodeTree(child) {\n    this.removeNode(child);\n    const { childNodes } = child;\n    childNodes.forEach((node) => this.removeNodeTree(node));\n  }\n}';
-      
-      let replaced = false;
-      
+
+      const newEventSource =
+        'class EventSource {\n  data = {};\n\n  get(id) {\n    return this.data[id];\n  }\n\n  set(id, value) {\n    this.data[id] = value;\n  }\n\n  delete(id) {\n    delete this.data[id];\n  }\n\n  has(id) {\n    return id in this.data;\n  }\n\n  removeNode(child) {\n    const { sid, uid } = child;\n    this.delete(sid);\n    if (uid !== sid && uid) this.delete(uid);\n  }\n\n  removeNodeTree(child) {\n    this.removeNode(child);\n    const { childNodes } = child;\n    childNodes.forEach((node) => this.removeNodeTree(node));\n  }\n}';
+
       // 方式1:查找并替换event-source.js模块
-      const eventSourceModulePattern = /\/\*\*\*\.\/node_modules\/@tarojs\/runtime\/dist\/dom\/event-source\.js[\s\S]*?class EventSource[\s\S]*?\/\*\*\*\/\s*\}\);/g;
-      
+      const eventSourceModulePattern =
+        /\/\*\*\*\.\/node_modules\/@tarojs\/runtime\/dist\/dom\/event-source\.js[\s\S]*?class EventSource[\s\S]*?\/\*\*\*\/\s*\}\);/g;
+
       if (eventSourceModulePattern.test(content)) {
         console.log('AlipayEventSourceFixPlugin: Found event-source.js module');
         const matches = content.match(eventSourceModulePattern);
         if (matches && matches.length > 0) {
           const oldModule = matches[0];
-          // 提取模块的开头部分
           const moduleStart = oldModule.substring(0, oldModule.indexOf('class EventSource'));
-          // 提取模块的结尾部分
           const moduleEnd = oldModule.substring(oldModule.lastIndexOf('*/') + 2);
-          // 构建新的模块内容
           const newModule = moduleStart + newEventSource + moduleEnd;
-          // 替换整个模块
           content = content.replace(oldModule, newModule);
           fs.writeFileSync(taroJsPath, content, 'utf8');
           console.log('AlipayEventSourceFixPlugin: Success: EventSource module replaced');
           replaced = true;
         }
       }
-      
+
       // 方式2:直接查找EventSource类定义
       if (!replaced) {
         const eventSourceStart = content.indexOf('class EventSource');
         if (eventSourceStart !== -1) {
           console.log('AlipayEventSourceFixPlugin: Found EventSource class');
-          // 查找类的结束位置
           let braceCount = 0;
           let eventSourceEnd = eventSourceStart;
           let foundOpeningBrace = false;
-          
+
           for (let i = eventSourceStart; i < content.length; i++) {
             if (content[i] === '{') {
               braceCount++;
@@ -70,15 +82,14 @@ class AlipayEventSourceFixPlugin {
             } else if (content[i] === '}') {
               braceCount--;
               if (foundOpeningBrace && braceCount === 0) {
-                eventSourceEnd = i + 1; // 包含结束大括号
+                eventSourceEnd = i + 1;
                 break;
               }
             }
           }
-          
+
           if (eventSourceEnd > eventSourceStart) {
             const oldEventSource = content.substring(eventSourceStart, eventSourceEnd);
-            // 替换为新的实现
             content = content.replace(oldEventSource, newEventSource);
             fs.writeFileSync(taroJsPath, content, 'utf8');
             console.log('AlipayEventSourceFixPlugin: Success: EventSource class replaced');
@@ -86,47 +97,14 @@ class AlipayEventSourceFixPlugin {
           }
         }
       }
-      
-      // 方式3:处理压缩后的EventSource类
-      if (!replaced) {
-        const compressedPattern = /class EventSource[^{]*\{[^}]*\{[^}]*\{[^}]*\}[^}]*\}[^}]*\}/g;
-        if (compressedPattern.test(content)) {
-          console.log('AlipayEventSourceFixPlugin: Found compressed EventSource');
-          const matches = content.match(compressedPattern);
-          if (matches && matches.length > 0) {
-            content = content.replace(matches[0], newEventSource);
-            fs.writeFileSync(taroJsPath, content, 'utf8');
-            console.log('AlipayEventSourceFixPlugin: Success: Compressed EventSource replaced');
-            replaced = true;
-          }
-        }
-      }
-      
-      // 方式4:处理语法错误的情况
-      if (!replaced && content.includes('class EventSource') && (content.includes('sid, uid') || content.includes('childNodes'))) {
-        console.log('AlipayEventSourceFixPlugin: Found EventSource with potential syntax errors');
-        // 查找EventSource开始位置
-        const eventSourceStart = content.indexOf('class EventSource');
-        if (eventSourceStart !== -1) {
-          // 查找一个合理的结束位置
-          const eventSourceEnd = content.indexOf('eventSource', eventSourceStart);
-          if (eventSourceEnd > eventSourceStart) {
-            // 提取从EventSource开始到eventSource变量定义之间的内容
-            const oldEventSource = content.substring(eventSourceStart, eventSourceEnd);
-            // 替换为新的实现
-            content = content.replace(oldEventSource, newEventSource);
-            fs.writeFileSync(taroJsPath, content, 'utf8');
-            console.log('AlipayEventSourceFixPlugin: Success: EventSource with syntax errors fixed');
-            replaced = true;
-          }
-        }
-      }
-      
+
       if (!replaced) {
         console.log('AlipayEventSourceFixPlugin: Info: EventSource not found or could not be replaced');
       }
-    } else {
-      console.log('AlipayEventSourceFixPlugin: Info: No EventSource found in dist/taro.js');
+    }
+
+    if (!replaced) {
+      console.log('AlipayEventSourceFixPlugin: Info: No EventSource pattern found in dist/taro.js');
     }
   }
 }

+ 53 - 42
scripts/fix-alipay-event-source.js

@@ -1,68 +1,79 @@
 const fs = require('fs');
 const path = require('path');
 
-// 修复支付宝小程序的EventSource错误
 function fixAlipayEventSource() {
   const taroJsPath = path.join(__dirname, '../dist/taro.js');
-  
+
   if (!fs.existsSync(taroJsPath)) {
     console.log('Error: dist/taro.js not found');
     return false;
   }
-  
+
   console.log('Fixing EventSource in dist/taro.js...');
-  
+
   let content = fs.readFileSync(taroJsPath, 'utf8');
-  
-  // 查找并替换EventSource类
+
+  const replacement =
+    'class EventSource{data={};get(e){return this.data[e]};set(e,t){this.data[e]=t};delete(e){delete this.data[e]};has(e){return e in this.data};removeNode(e){const{sid:t,uid:n}=e;this.delete(t);n!==t&&n&&this.delete(n)};removeNodeTree(e){this.removeNode(e);const{childNodes:t}=e;t.forEach(e=>this.removeNodeTree(e))}}const r=new EventSource';
+
+  // Taro 4.x: 类名被压缩 (如 class i extends Map) → 通过 removeNode 特征匹配
+  const minifiedPattern =
+    /class \w+ extends Map\{removeNode\([\s\S]*?removeNodeTree\([\s\S]*?\}\}const r=new \w+/g;
+
+  if (minifiedPattern.test(content)) {
+    content = content.replace(minifiedPattern, replacement);
+    fs.writeFileSync(taroJsPath, content, 'utf8');
+    console.log('Success: Minified EventSource (Map) fixed');
+    return true;
+  }
+
+  // Taro 3.x: 未压缩的 class EventSource extends Map
   const oldEventSource = /class EventSource extends Map \{[\s\S]*?\}/g;
   const newEventSource = `class EventSource {
-	data = {};
-
-	get(id) {
-		return this.data[id];
-	}
-
-	set(id, value) {
-		this.data[id] = value;
-	}
-
-	delete(id) {
-		delete this.data[id];
-	}
-
-	has(id) {
-		return id in this.data;
-	}
-
-	removeNode(child) {
-		const { sid, uid } = child;
-		this.delete(sid);
-		if (uid !== sid && uid) this.delete(uid);
-	}
-
-	removeNodeTree(child) {
-		this.removeNode(child);
-		const { childNodes } = child;
-		childNodes.forEach((node) => this.removeNodeTree(node));
-	}
-}`;
-  
+    data = {};
+
+    get(id) {
+      return this.data[id];
+    }
+
+    set(id, value) {
+      this.data[id] = value;
+    }
+
+    delete(id) {
+      delete this.data[id];
+    }
+
+    has(id) {
+      return id in this.data;
+    }
+
+    removeNode(child) {
+      const { sid, uid } = child;
+      this.delete(sid);
+      if (uid !== sid && uid) this.delete(uid);
+    }
+
+    removeNodeTree(child) {
+      this.removeNode(child);
+      const { childNodes } = child;
+      childNodes.forEach((node) => this.removeNodeTree(node));
+    }
+  }`;
+
   if (oldEventSource.test(content)) {
     content = content.replace(oldEventSource, newEventSource);
     fs.writeFileSync(taroJsPath, content, 'utf8');
     console.log('Success: EventSource fixed');
     return true;
-  } else {
-    console.log('Info: EventSource pattern not found, skipping');
-    return false;
   }
+
+  console.log('Info: EventSource pattern not found, skipping');
+  return false;
 }
 
-// 导出函数
 module.exports = fixAlipayEventSource;
 
-// 如果直接运行此脚本
 if (require.main === module) {
   fixAlipayEventSource();
 }