'use strict'; var debug = require('debug'); var uniCliShared = require('@dcloudio/uni-cli-shared'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var debug__default = /*#__PURE__*/_interopDefault(debug); function once(fn, ctx = null) { let res; return ((...args) => { if (fn) { res = fn.apply(ctx, args); fn = null; } return res; }); } /** * 解析当前平台对应的 manifest 平台节点。 * * 与 `uni-cli-shared#getPlatformManifestJson` 行为保持一致:app → app-plus/plus, * h5 → web/h5,uni-app x 的 app-android/app-ios/app 走各自分支,其余平台取同名节点。 * * 逻辑内聚在 uni-stat 插件内(仅依赖 `parseManifestJsonOnce`),避免依赖 * HBuilderX 内置旧版 uni-cli-shared 可能缺失的新导出(如 `getUniStatistics`)。 * * @param manifest 已解析的 manifest.json 对象 * @param platform 目标平台;缺省读 `process.env.UNI_PLATFORM` */ function getPlatformManifest(manifest, platform) { const isX = process.env.UNI_APP_X === 'true'; if (!platform) { platform = process.env.UNI_PLATFORM; } if (isX) { if (platform === 'app-android' || platform === 'app-ios') { return (manifest === null || manifest === void 0 ? void 0 : manifest[platform]) || (manifest === null || manifest === void 0 ? void 0 : manifest['app']) || {}; } else if (platform === 'app') { return ((manifest === null || manifest === void 0 ? void 0 : manifest[process.env.UNI_UTS_PLATFORM]) || (manifest === null || manifest === void 0 ? void 0 : manifest['app']) || {}); } } if (platform === 'app') { return (manifest === null || manifest === void 0 ? void 0 : manifest['app-plus']) || (manifest === null || manifest === void 0 ? void 0 : manifest['plus']) || {}; } if (platform === 'h5') { return (manifest === null || manifest === void 0 ? void 0 : manifest.web) || (manifest === null || manifest === void 0 ? void 0 : manifest.h5) || {}; } return (platform && (manifest === null || manifest === void 0 ? void 0 : manifest[platform])) || {}; } /** * 根据 manifest 判定是否自动开启统计(是否向 main 注入统计运行时)。 * * ## 范围 * * 仅控制 `shouldAutoImportStatRuntime`;**不**影响 `plugin/index.ts` 对 * `UNI_STATISTICS_CONFIG` 等 define 的注入(配置合并仍走 `getUniStatistics`)。 * * ## enable 判定规则(仅以 `enable` 是否显式存在作为覆盖条件) * * 子平台存在 `uniStatistics` 但只配置了 `debug` / `reportInterval` 等、未写 `enable` 时, * **不视为**子节点覆盖,仍继承根节点 `enable`。 * * 判定顺序: * 1. 子平台 `uniStatistics.enable` 已显式配置(`true` / `false`)→ 以子为准; * 2. 否则,根 `uniStatistics.enable` 已显式配置 → 继承根; * 3. 否则(根/子均无 `enable`,或均无 `uniStatistics` 节点)→ **默认开启**。 * * ## 用例矩阵 * * | 根 enable | 子 uniStatistics | 子 enable | 结果 | * |-----------|------------------|-----------|--------| * | false | 有 | true | 开启 | * | true | 有 | false | 关闭 | * | true | 无 | — | 开启 | * | false | 无 | — | 关闭 | * | false | 有(仅 debug 等)| 未配置 | 关闭 | * | 无节点 | 有 | true | 开启 | * | 无节点 | 有 | false | 关闭 | * | 无节点 | 无 | — | 开启 | * | 无节点 | 有(仅非 enable)| 未配置 | 开启 | * * @param inputDir 工程输入目录 * @param platform 目标平台;缺省读 `process.env.UNI_PLATFORM` */ function isUniStatisticsEnabled(inputDir, platform) { var _a; const manifest = uniCliShared.parseManifestJsonOnce(inputDir); const root = manifest === null || manifest === void 0 ? void 0 : manifest.uniStatistics; const platformStat = (_a = getPlatformManifest(manifest, platform)) === null || _a === void 0 ? void 0 : _a.uniStatistics; if (platformStat && platformStat.enable !== undefined) { return platformStat.enable !== false; } if (root && root.enable !== undefined) { return root.enable !== false; } return true; } /** * 当前是否为 uni-app x 编译目标。 * x 运行时暂无 `onCreateVueApp` / `vue.mixin` 等页面统计注入能力。 */ function isUniAppXCompile() { return process.env.UNI_APP_X === 'true'; } /** * 是否应向 main 入口自动 import 统计运行时。 * uni-app x 一律跳过自动 import;define 配置注入仍保留,供后续适配或业务手动 import。 * * @param inputDir 工程输入目录 * @param platform 目标平台;缺省读 `process.env.UNI_PLATFORM`。传入以支持分平台 enable 覆盖。 */ function shouldAutoImportStatRuntime(inputDir, platform) { if (isUniAppXCompile()) { return false; } return isUniStatisticsEnabled(inputDir, platform); } /** * 解析统计版本类型(公有版 / 私有版)。 * - 优先 `type`;缺失时回退旧版 `version`(2=private,其余=public)。 */ function resolveUniStatisticsType(statConfig) { var _a; const type = String((_a = statConfig === null || statConfig === void 0 ? void 0 : statConfig.type) !== null && _a !== void 0 ? _a : '').trim(); if (type === 'public' || type === 'private') { return type; } const versionNum = Number(statConfig === null || statConfig === void 0 ? void 0 : statConfig.version); return versionNum === 2 ? 'private' : 'public'; } const uniStatLog = once((text) => { console.log(); console.warn(text); console.log(); }); /** 与 `public/config.ts#MP_WEIXIN_USE_PRELOAD_ASSETS_REPORT` 保持一致。 */ const MP_WEIXIN_USE_PRELOAD_ASSETS_REPORT = true; /** 公有版小程序 GET 上报域名(与 `public/config.ts#IMAGE_REPORT_DEFAULTS.host` 一致)。 */ const STAT_MP_REQUEST_DOMAIN = 'tongji-collector.dcloud.net.cn'; const STAT_MP_DOMAIN_DOC_URL = 'https://uniapp.dcloud.net.cn/uni-stat-public.html'; /** * 构建期「统计已开启」提示文案(不依赖 i18n 占位符,避免 HBuilderX 内置文案仍为 `{version}` 时原样输出)。 * - public:已开启 uni 统计 2.0 * - private:已开启 uni 统计 2.0(私有版) */ function formatStatEnabledTip(statType) { return statType === 'private' ? '已开启 uni统计 2.0(私有版)' : '已开启 uni统计 2.0'; } /** * 构建期小程序 request 合法域名提示(单条合并「已开启」与域名说明)。 */ function formatMpStatDomainTip() { return `已开启 uni统计 2.0,为保障数据正常上报,请在小程序后台配置 request 合法域名:${STAT_MP_REQUEST_DOMAIN}。详情:${STAT_MP_DOMAIN_DOC_URL}`; } /** * 是否需要在构建期提示配置小程序 request 合法域名。 * 微信默认 preload 信标不走 uni.request,无需配置;开关关闭时与其它小程序一致。 */ function shouldShowMpDomainTip(platform, statType) { if (statType !== 'public' || !platform.startsWith('mp-')) { return false; } if (platform === 'mp-weixin' && MP_WEIXIN_USE_PRELOAD_ASSETS_REPORT) { return false; } return true; } /** * 输出构建期「统计已开启」提示:小程序公有版(需配置域名)走合并文案,其余走简短文案。 */ function logStatEnabledTip(platform, statType) { if (shouldShowMpDomainTip(platform, statType)) { uniStatLog(formatMpStatDomainTip()); return; } uniStatLog(formatStatEnabledTip(statType)); } var index = () => [ uniCliShared.defineUniMainJsPlugin((opts) => { /** * 统计类型(仅用于新编译器): * - public:公有版(uni-stat-public) * - private:私有版(uni-cloud-stat) * * 兼容策略: * - 优先读取 manifest.uniStatistics.type(public/private) * - type 缺失或非法时,回退旧版 version(2=private,其余=public) */ let statType = 'public'; let isEnable = false; const stats = { '@dcloudio/uni-stat': uniCliShared.resolveBuiltIn('@dcloudio/uni-stat/dist/uni-stat.es.js'), '@dcloudio/uni-cloud-stat': uniCliShared.resolveBuiltIn('@dcloudio/uni-stat/dist/uni-cloud-stat.es.js'), '@dcloudio/uni-stat-public': uniCliShared.resolveBuiltIn('@dcloudio/uni-stat/dist/uni-stat-public.es.js'), }; return { name: 'uni:stat', enforce: 'pre', config(config, env) { var _a, _b, _c, _d, _e; if (!uniCliShared.isNormalCompileTarget()) { // 不需要统计 return; } const inputDir = process.env.UNI_INPUT_DIR; const platform = process.env.UNI_PLATFORM; const titlesJson = Object.create(null); uniCliShared.parsePagesJson(inputDir, platform).pages.forEach((page) => { var _a; const style = page.style || {}; const titleText = // MP style.navigationBarTitleText || ( // H5 || App (_a = style.navigationBar) === null || _a === void 0 ? void 0 : _a.titleText) || ''; if (titleText) { titlesJson[page.path] = titleText; } }); // 注意:勿在此对 mp- + UNI_APP_X 提前 return。 // 提前 return 会导致后续未执行 getUniStatistics / UNI_STATISTICS_CONFIG, // 小程序公有版运行时 manifest(backgroundTimeout / reportInterval 等)全部丢失,仍走默认值; // H5 不走 mp- 分支故无此问题。标题 JSON 与统计配置在同一套 define 末尾统一注入。 // ssr 时不开启 if (!uniCliShared.isSsr(env.command, config)) { const statConfig = uniCliShared.getUniStatistics(inputDir, platform); // 始终注入完整 manifest.uniStatistics(与 enable 无关)。 // enable 仅控制是否自动 import 统计入口;业务手动 import 或 enable:false 调试时, // 运行时仍须能读到 backgroundTimeout / reportInterval 等字段。 process.env.UNI_STATISTICS_CONFIG = JSON.stringify(statConfig); process.env.UNI_STAT_DEBUG = statConfig.debug ? 'true' : 'false'; // enable 开关:仅以子/根 `enable` 是否显式存在为准(子优先 → 继承根 → 默认开启), // 详见 `runtimeEnable.ts#isUniStatisticsEnabled` 用例矩阵。 // uni-app x 不支持自动 import(见 shouldAutoImportStatRuntime),但仍注入 define 配置。 isEnable = shouldAutoImportStatRuntime(inputDir, platform); statType = resolveUniStatisticsType(statConfig); if (isEnable) { const uniCloudConfig = statConfig.uniCloud || {}; process.env.UNI_STAT_UNI_CLOUD = JSON.stringify(uniCloudConfig); // 公有版字段 `an` 兜底:注入 manifest.json#name 到 process.env.UNI_APP_NAME, // 由 `public/adapter/package.ts#getEnvAppName` 读取。任意阶段读 manifest 失败 // 都走 try/catch,不阻断构建。 try { const manifestForName = uniCliShared.parseManifestJsonOnce(inputDir); if (manifestForName && typeof manifestForName.name === 'string') { process.env.UNI_APP_NAME = manifestForName.name; } } catch (e) { debug__default.default('uni:stat')('parse manifest for UNI_APP_NAME failed', e); } if (process.env.NODE_ENV === 'production') { const manifestJson = uniCliShared.parseManifestJsonOnce(inputDir); if (!manifestJson.appid) { uniStatLog(uniCliShared.M['stat.warn.appid']); isEnable = false; } else { logStatEnabledTip(platform, statType); } } else { logStatEnabledTip(platform, statType); } } debug__default.default('uni:stat')('isEnable', isEnable, 'type', statType); } process.env.UNI_STAT_TITLE_JSON = JSON.stringify(titlesJson); return { define: { // 与 UNI_APP_NAME 同理:外层 JSON.stringify 才能得到合法的内联字符串字面量 'process.env.UNI_STAT_TITLE_JSON': JSON.stringify((_a = process.env.UNI_STAT_TITLE_JSON) !== null && _a !== void 0 ? _a : '{}'), 'process.env.UNI_STAT_UNI_CLOUD': JSON.stringify((_b = process.env.UNI_STAT_UNI_CLOUD) !== null && _b !== void 0 ? _b : '{}'), // 注意:define 的 value 是「替换后的源码字面量」,必须 JSON.stringify 一次, // 否则 'true' / 'false' 字符串会被当成布尔字面量替换进源码,导致 // dist 中 `process.env.UNI_STAT_DEBUG === 'true'` 永远等于 false(公有版调试日志失效根因)。 'process.env.UNI_STAT_DEBUG': JSON.stringify((_c = process.env.UNI_STAT_DEBUG) !== null && _c !== void 0 ? _c : 'false'), // 与 UNI_STAT_TITLE_JSON 同理:`statConfig` 已是 JSON 字符串,若不经 // JSON.stringify 再包一层,esbuild/vite define 会把串内 `"` 当成源码边界, // 运行时替换结果残缺 → JSON.parse 失败 → readManifestStatConfig 静默回退, // manifest 里的 backgroundTimeout / pageInactiveTimeout 等全部丢失(表现为默认 300/1800)。 'process.env.UNI_STATISTICS_CONFIG': JSON.stringify((_d = process.env.UNI_STATISTICS_CONFIG) !== null && _d !== void 0 ? _d : '{}'), 'process.env.UNI_APP_NAME': JSON.stringify((_e = process.env.UNI_APP_NAME) !== null && _e !== void 0 ? _e : ''), }, }; }, resolveId(id) { return stats[id] || null; }, transform(code, id) { if (isEnable && opts.filter(id)) { // 新编译器只保留类型分流: // public → @dcloudio/uni-stat-public // private → @dcloudio/uni-cloud-stat // // 兼容旧配置: // type 缺失时回退 version(2=private,其余=public) const importPath = statType === 'private' ? '@dcloudio/uni-cloud-stat' : '@dcloudio/uni-stat-public'; return { code: code + `;import '${importPath}';`, map: null, }; } }, }; }), ]; module.exports = index;