# 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) ```javascript 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) ```javascript // 核心导航函数 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) ```javascript // 守卫钩子列表 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) ```javascript // 代理页面生命周期钩子 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) ```javascript /** * 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 详细功能 #### 路由配置选项 ```javascript { // 平台类型 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) {} } ``` #### 路由对象结构 ```javascript { name: "index", // 路由名称 path: "/pages/index/index", // 路径 fullPath: "/pages/index/index?id=1", // 完整路径 query: { id: "1" }, // 查询参数 params: {}, // 路由参数 meta: {}, // 元信息 NAVTYPE: "push", // 导航类型 BACKTYPE: "" // 返回类型 } ``` #### API方法 ```javascript // 导航方法 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 ``` #### 原生方法重写 ```javascript // 重写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+个,这里仅列出主要模块。