Files
integral-resell/h5/static/js/chunk-vendors.4d47960d.ANALYSIS.md

17 KiB
Executable File
Raw Blame History

chunk-vendors.4d47960d.js 详细分析

文件信息

  • 文件名: chunk-vendors.4d47960d.js
  • 大小: 1.18MB (1,181,721 bytes)
  • 类型: Webpack第三方依赖打包文件
  • 压缩: 高度压缩约26行
  • 模块数: 约200+个模块

文件用途

这是Webpack打包的第三方依赖库文件包含应用所需的所有外部库和polyfills。主要包括

  • uni-simple-router完整路由库
  • 加密库HMAC, SHA, MD5等
  • Buffer实现
  • 各种Polyfills

主要库分类

1. uni-simple-router 路由库

这是核心依赖,占据了大部分代码量。

核心模块

模块ID 名称 功能
607 主入口 导出createRouter, RouterMount等
366 常量定义 hookToggle, navtypeToggle等
309 类型定义 TypeScript类型声明
169 钩子调用 loopCallHook, transitionTo等
890 导航跳转 navjump, lockNavjump, createRoute
845 页面钩子 proxyPageHook, createFullPath
99 查询参数 queryPageToMap, parseQuery
314 方法重写 rewriteMethod
963 路由创建 createRouter, RouterMount
809 原生跳转 uniOriginJump
662 钩子注册 registerEachHooks
460 Mixins initMixins, getMixins
789 工具函数 deepClone, getDataType等
883 日志工具 err, warn, log
282 配置常量 baseConfig, proxyHookName
801 路由映射 createRouteMap
814 加载页面 registerLoddingPage
334 路径获取 getEnterPath
779 路径匹配 pathToRegexp

功能详解

路由创建 (模块 963)
function createRouter(options) {
  return {
    // 配置
    options,
    mount: [],
    Vue: null,
    routesMap: {},
    
    // 导航方法
    push(location) { ... },
    replace(location) { ... },
    replaceAll(location) { ... },
    pushTab(location) { ... },
    back(delta, options) { ... },
    
    // 守卫
    beforeEach(fn) { ... },
    afterEach(fn) { ... },
    
    // 安装
    install(Vue) { ... }
  };
}
导航跳转 (模块 890)
// 核心导航函数
function navjump(rule, router, NAVTYPE, forceNav, uniActualData, callback, passthrough) {
  // 1. 处理back类型
  if (NAVTYPE === "back") {
    // 构建返回参数
  }
  
  // 2. 解析路由
  var query = queryPageToMap(rule, router).rule;
  query.type = navtypeToggle[NAVTYPE];
  
  // 3. 处理params到query
  var finalRule = paramsToQuery(router, query);
  var resolvedRule = resolveQuery(finalRule, router);
  
  // 4. H5平台特殊处理
  if (router.options.platform === "h5") {
    if (NAVTYPE !== "push") NAVTYPE = "replace";
    
    if (forceNav != null) {
      forceNav.next({ replace: NAVTYPE !== "push", ...resolvedRule });
    } else {
      router.$route[NAVTYPE](resolvedRule);
    }
  } 
  // 5. 小程序/App平台
  else {
    // 创建to和from
    var to = createToFrom(resolvedRule, router);
    var from = getCurrentRoute(router);
    
    createFullPath(resolvedRule, from);
    
    if (!passthrough) {
      return resolvedRule;
    }
    
    // 触发守卫
    transitionTo(router, resolvedRule, from, NAVTYPE, HOOKLIST, function(next) {
      uni[navtypeToggle[NAVTYPE]](resolvedRule, true, next, callback);
    });
  }
}

// 带锁的导航
function lockNavjump(rule, router, NAVTYPE, forceNav, uniActualData) {
  lockDetectWarn(router, rule, NAVTYPE, function() {
    // H5不锁定
    if (router.options.platform !== "h5") {
      router.$lockStatus = true;
    }
    navjump(rule, router, NAVTYPE, void 0, forceNav, uniActualData);
  }, uniActualData);
}
路由守卫 (模块 169)
// 守卫钩子列表
var HOOKLIST = [
  // 1. 全局前置守卫
  function(router, to, from, route, next) {
    callHook(router.lifeCycle.routerBeforeHooks[0], to, from, router, next);
  },
  
  // 2. 组件beforeRouteLeave
  function(router, to, from, route, next) {
    callBeforeRouteLeave(router, to, from, next);
  },
  
  // 3. 路由beforeHooks
  function(router, to, from, route, next) {
    callHook(router.lifeCycle.beforeHooks[0], to, from, router, next);
  },
  
  // 4. 路由独享守卫beforeEnter
  function(router, to, from, route, next) {
    callHook(route.beforeEnter, to, from, router, next);
  },
  
  // 5. 路由afterHooks
  function(router, to, from, route, next) {
    router.$lockStatus = false;
    
    if (router.options.platform === "h5") {
      proxyH5Mount(router);
    }
    
    callHook(router.lifeCycle.afterHooks[0], to, from, router, next, false);
  },
  
  // 6. 全局后置守卫
  function(router, to, from, route, next) {
    router.$lockStatus = false;
    
    if (router.options.platform === "h5") {
      proxyH5Mount(router);
    }
    
    callHook(router.lifeCycle.routerAfterHooks[0], to, from, router, next, false);
  }
];

// 循环调用钩子
function loopCallHook(hooks, index, next, router, to, from, NAVTYPE) {
  // 如果所有钩子都执行完了
  if (hooks.length - 1 < index) {
    return next();
  }
  
  var hook = hooks[index];
  var errorHook = ERRORHOOK[0];
  
  // 调用钩子
  hook(router, to, from, route, function(nextRule) {
    // App平台tab切换特殊处理
    if (router.options.platform === "app-plus") {
      if (nextRule !== false && 
          typeof nextRule !== "string" && 
          typeof nextRule !== "object") {
        tabIndexSelect(to, from);
      }
    }
    
    // 1. next(false) - 终止导航
    if (nextRule === false) {
      if (router.options.platform === "h5") {
        next(false);
      }
      errorHook({
        type: 0,
        msg: "管道函数传递 false 导航被终止!",
        matTo: to,
        matFrom: from,
        nextTo: nextRule
      }, router);
    }
    // 2. next(string|object) - 重定向
    else if (typeof nextRule === "string" || typeof nextRule === "object") {
      var redirectNAVTYPE = NAVTYPE;
      var redirectRule = nextRule;
      
      if (typeof nextRule === "object") {
        var NAVTYPE_OVERRIDE = nextRule.NAVTYPE;
        redirectRule = objectWithoutProperties(nextRule, ["NAVTYPE"]);
        
        if (NAVTYPE_OVERRIDE != null) {
          redirectNAVTYPE = NAVTYPE_OVERRIDE;
        }
      }
      
      navjump(redirectRule, router, redirectNAVTYPE, { from, next });
    }
    // 3. next() - 继续
    else if (nextRule == null) {
      index++;
      loopCallHook(hooks, index, next, router, to, from, NAVTYPE);
    }
    // 4. 其他 - 错误
    else {
      errorHook({
        type: 1,
        msg: "管道函数传递未知类型,无法被识别。导航被终止!",
        matTo: to,
        matFrom: from,
        nextTo: nextRule
      }, router);
    }
  });
}

// 转换导航
function transitionTo(router, to, from, NAVTYPE, hooks, finalCallback) {
  var formattedRoutes = forMatNextToFrom(router, to, from);
  var matTo = formattedRoutes.matTo;
  var matFrom = formattedRoutes.matFrom;
  
  // H5平台
  if (router.options.platform === "h5") {
    loopCallHook(hooks, 0, finalCallback, router, matTo, matFrom, NAVTYPE);
  }
  // 小程序/App平台
  else {
    // 分两步执行钩子
    // 第一步前4个钩子
    loopCallHook(hooks.slice(0, 4), 0, function() {
      // 第二步后2个钩子在导航完成后
      finalCallback(function() {
        loopCallHook(hooks.slice(4), 0, voidFun, router, matTo, matFrom, NAVTYPE);
      });
    }, router, matTo, matFrom, NAVTYPE);
  }
}
页面钩子代理 (模块 845)
// 代理页面生命周期钩子
function proxyPageHook(vueInstance, router, mpType) {
  var proxyHookDeps = router.proxyHookDeps;
  var options = vueInstance.$options;
  
  var proxyHookNames = [
    "onLoad", "onShow", "onReady", "onHide", 
    "onUnload", "onPullDownRefresh", "onReachBottom"
  ];
  
  for (var i = 0; i < proxyHookNames.length; i++) {
    var hookName = proxyHookNames[i];
    var hooks = options[hookName];
    
    if (hooks) {
      for (var j = 0; j < hooks.length; j++) {
        // 跳过已代理的钩子
        if (hooks[j].toString().includes("UNI-SIMPLE-ROUTER")) {
          continue;
        }
        
        var hookId = Object.keys(proxyHookDeps.hooks).length + 1;
        
        // 创建代理函数
        var proxyHook = function() {
          var args = Array.prototype.slice.call(arguments);
          proxyHookDeps.resetIndex.push(hookId);
          proxyHookDeps.options[hookId] = args;
        };
        
        // 保存原始钩子
        var originalHook = hooks.splice(j, 1, proxyHook)[0];
        
        // 保存钩子信息
        proxyHookDeps.hooks[hookId] = {
          proxyHook: proxyHook,
          callHook: function(path) {
            // 只在匹配路径时调用
            if (router.enterPath.replace(/^\//, "") === path.replace(/^\//, "") ||
                mpType === "app") {
              var args = proxyHookDeps.options[hookId];
              originalHook.apply(vueInstance, args);
            }
          },
          resetHook: function() {
            hooks.splice(j, 1, originalHook);
          }
        };
      }
    }
  }
}

// 重置并调用页面钩子
function resetAndCallPageHook(router, path, reset) {
  if (reset === void 0) reset = true;
  
  // 解析路径
  var match = path.trim().match(/^(\/?[^\?\s]+)(\?[\s\S]*$)?$/);
  if (match == null) {
    throw new Error("还原hook失败。请检查 【" + path + "】 路径是否正确。");
  }
  path = match[1];
  
  var proxyHookDeps = router.proxyHookDeps;
  var resetIndex = proxyHookDeps.resetIndex;
  
  // 调用所有钩子
  for (var i = 0; i < resetIndex.length; i++) {
    var hookId = resetIndex[i];
    proxyHookDeps.hooks[hookId].callHook(path);
  }
  
  // 重置钩子
  if (reset) {
    resetPageHook(router);
  }
}

2. 加密库

HMAC (模块 0116)

/**
 * HMAC - Hash-based Message Authentication Code
 * 
 * 算法:
 * HMAC(K, m) = H((K ⊕ opad) || H((K ⊕ ipad) || m))
 * 
 * 其中:
 * - K: 密钥
 * - m: 消息
 * - H: 哈希函数
 * - ⊕: XOR运算
 * - ||: 连接
 * - ipad: 0x36重复blocksize次
 * - opad: 0x5C重复blocksize次
 */

function Hmac(alg, key) {
  // 1. 如果key是字符串转为Buffer
  if (typeof key === "string") {
    key = Buffer.from(key);
  }
  
  // 2. 确定blocksize
  var blocksize = (alg === "sha512" || alg === "sha384") ? 128 : 64;
  
  // 3. 处理key长度
  if (key.length > blocksize) {
    // key太长先hash
    var hash = (alg === "rmd160") ? new rmd160() : sha(alg);
    key = hash.update(key).digest();
  } else if (key.length < blocksize) {
    // key太短填充0
    key = Buffer.concat([key, zeroBuffer], blocksize);
  }
  
  // 4. 计算ipad和opad
  var ipad = Buffer.allocUnsafe(blocksize);
  var opad = Buffer.allocUnsafe(blocksize);
  
  for (var i = 0; i < blocksize; i++) {
    ipad[i] = key[i] ^ 0x36;
    opad[i] = key[i] ^ 0x5C;
  }
  
  // 5. 初始化内部hash
  this._hash = (alg === "rmd160") ? new rmd160() : sha(alg);
  this._hash.update(ipad);
}

Hmac.prototype._final = function() {
  // 1. 计算内部hash
  var innerHash = this._hash.digest();
  
  // 2. 计算外部hash
  var hash = (this._alg === "rmd160") ? new rmd160() : sha(this._alg);
  return hash.update(this._opad).update(innerHash).digest();
};

支持的算法:

  • MD5
  • SHA1, SHA256, SHA384, SHA512
  • RIPEMD160

Cipher (模块 0168)

加密/解密基类,提供:

  • 缓冲区管理
  • 分块处理
  • 填充处理

Buffer (模块 5f79)

Node.js Buffer在浏览器环境的实现。


3. 核心Polyfills

Object方法

模块ID 方法 说明
00ca getOwnPropertyNames 获取对象自身属性名
036b indexOf 数组indexOf
338c hasOwnProperty 检查自身属性
f660 toIndexedObject 转为索引对象

Array方法

模块ID 方法 说明
bb80 push 数组push
00c2 keys 对象键名

工具函数

模块ID 功能 说明
2c2e inherits 继承工具
cfef Transform 流转换
d3c2 assert 断言

4. uni-simple-router 详细功能

路由配置选项

{
  // 平台类型
  platform: "h5" | "app-plus" | "mp-weixin" | "mp-alipay" | ...,
  
  // 路由表
  routes: [
    {
      path: "/pages/index/index",
      name: "index",
      aliasPath: "/",
      meta: {},
      beforeEnter: function(to, from, next) {}
    }
  ],
  
  // H5配置
  h5: {
    vueRouterDev: false,
    vueNext: false,
    paramsToQuery: false
  },
  
  // 小程序配置
  applet: {
    animationDuration: 300
  },
  
  // App配置
  APP: {
    animation: {
      animationType: "pop-in",
      animationDuration: 300
    },
    launchedHook: function() {}
  },
  
  // 调试
  debugger: false | true | { err: true, warn: true, log: false },
  
  // 守卫
  routerBeforeEach: function(to, from, next) {},
  routerAfterEach: function(to, from) {},
  routerErrorEach: function(error, router) {},
  
  // 查询处理
  resolveQuery: function(query) { return query; },
  parseQuery: function(query) { return query; },
  
  // 检测锁
  detectBeforeLock: function(router, to, navType) {}
}

路由对象结构

{
  name: "index",           // 路由名称
  path: "/pages/index/index",  // 路径
  fullPath: "/pages/index/index?id=1",  // 完整路径
  query: { id: "1" },      // 查询参数
  params: {},              // 路由参数
  meta: {},                // 元信息
  NAVTYPE: "push",         // 导航类型
  BACKTYPE: ""             // 返回类型
}

API方法

// 导航方法
router.push(location)
router.replace(location)
router.replaceAll(location)
router.pushTab(location)
router.back(delta, options)

// 守卫方法
router.beforeEach(fn)
router.afterEach(fn)

// 强制触发
router.forceGuardEach(NAVTYPE, passthrough)

// Vue实例访问
this.$Router    // 路由器实例
this.$Route     // 当前路由
this.$AppReady  // App准备完成Promise

原生方法重写

// 重写uni原生导航方法
uni.navigateTo(options)     router.push()
uni.redirectTo(options)     router.replace()
uni.reLaunch(options)       router.replaceAll()
uni.switchTab(options)      router.pushTab()
uni.navigateBack(options)   router.back()

模块依赖关系

607 (主入口)
├── 366 (常量)
├── 309 (类型)
├── 814 (加载页面)
└── 963 (创建路由)
    ├── 282 (配置)
    ├── 789 (工具)
    ├── 662 (钩子注册)
    ├── 460 (Mixins)
    │   ├── 801 (路由映射)
    │   ├── 844 (Vue路由)
    │   ├── 147 (代理)
    │   └── 814 (加载页面)
    ├── 890 (导航)
    │   ├── 366 (常量)
    │   ├── 99 (查询)
    │   ├── 789 (工具)
    │   ├── 169 (钩子调用)
    │   └── 845 (页面钩子)
    └── 314 (方法重写)
        └── 809 (原生跳转)

性能优化

1. 代码分割

  • 将第三方库独立打包
  • 减少主bundle大小
  • 利用浏览器缓存

2. 懒加载

  • 页面组件按需加载
  • 减少首屏加载时间

3. 压缩

  • UglifyJS压缩
  • 变量名混淆
  • 移除注释和空格

建议

1. 优化建议

  • 使用CDN加载常用库
  • 启用Gzip/Brotli压缩
  • 考虑按需引入uni-simple-router功能
  • 分析是否所有加密库都需要

2. 调试建议

  • 使用Source Map调试
  • 启用路由debugger选项
  • 查看原始源代码

3. 升级建议

  • 检查依赖库版本
  • 及时更新安全补丁
  • 关注性能优化

总结

chunk-vendors.4d47960d.js 是一个包含所有第三方依赖的大型文件:

主要内容:

  1. uni-simple-router (约70%代码量)
  2. 加密库 (HMAC, SHA, MD5等)
  3. Buffer实现
  4. Polyfills (Object, Array方法)
  5. 工具函数

特点:

  • 📦 高度压缩1.18MB → 约26行
  • 🔒 变量混淆
  • 模块化设计
  • 🎯 独立打包

用途:

  • 提供路由功能
  • 提供加密功能
  • 兼容性支持
  • 工具函数库

由于文件过大且高度压缩,完整反编译需要原始源代码和构建配置。建议查看:

  • uni-simple-router GitHub仓库
  • 项目的package.json
  • Webpack配置文件

附录模块ID速查表

uni-simple-router核心模块

  • 607: 主入口
  • 366: 常量定义
  • 963: 创建路由器
  • 890: 导航跳转
  • 169: 钩子调用
  • 845: 页面钩子
  • 789: 工具函数
  • 99: 查询参数
  • 314: 方法重写
  • 662: 钩子注册
  • 460: Mixins
  • 282: 配置常量

加密相关

  • 0116: HMAC
  • 0168: Cipher
  • 5f79: Buffer
  • 1177: MD5
  • 2d81: RMD160
  • 25a4: SHA

Polyfills

  • 00c2: indexOf
  • 00ca: getOwnPropertyNames
  • bb80: array push
  • 338c: hasOwnProperty
  • f660: toIndexedObject

完整模块列表约200+个,这里仅列出主要模块。