17 KiB
Executable File
17 KiB
Executable File
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 是一个包含所有第三方依赖的大型文件:
主要内容:
- ✅ uni-simple-router (约70%代码量)
- ✅ 加密库 (HMAC, SHA, MD5等)
- ✅ Buffer实现
- ✅ Polyfills (Object, Array方法)
- ✅ 工具函数
特点:
- 📦 高度压缩(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+个,这里仅列出主要模块。