#!/usr/bin/env node /** * E 批:图片 lazy-load 治理 * 在长列表页的 标签上补 lazy-load(若尚未有 lazy-load 属性) * * 策略: * - 对 不含 lazy-load 的标签补上 lazy-load * - 跳过已有 lazy-load 的标签 * - 仅处理已识别的长列表页(discover / article-center / shop / activity / growth 等) */ const fs = require('fs') const path = require('path') const ROOT = path.resolve(__dirname, '..') const EXCLUDE_DIRS = new Set(['node_modules', 'dist', 'unpackage', '.git', 'docs']) // 需要治理的长列表页面/组件(按父目录分组,walk 时过滤) const TARGET_PATTERNS = [ 'pages/discover/', 'pages/article-center/', 'pages/shop/', 'pages/activity/', 'pages/growth/', 'pages/promotion/', 'components/DimensionActivities.vue', 'components/DimensionProducts.vue', 'components/RecommendedFeed.vue', 'components/ArticleBookshelf.vue', 'components/FamilyFeed.vue', 'components/daily-task-card.vue', ] // 模式:找到 中不含 lazy-load 的,加上 lazy-load // 匹配:(不含 lazy-load),在后面某个位置补 const IMG_TAG_RE = /]*)>/gi function processFile(filePath) { const src = fs.readFileSync(filePath, 'utf8') // 只处理包含长列表 image 的文件(启发式:有 v-for 或 list/data 字样的文件优先) const hasLoop = /v-for\s*=/.test(src) || /v_loop/.test(src) if (!hasLoop) return { changed: false, count: 0 } let result = src let count = 0 result = result.replace(IMG_TAG_RE, (fullMatch, attrs) => { if (/lazy-load/.test(attrs)) return fullMatch // 已有 lazy-load,跳过 // 在标签闭合 `>`(可能为 `/>`)前插入 lazy-load if (fullMatch.endsWith('/>')) { return fullMatch.slice(0, -2) + ' lazy-load />' } return fullMatch.slice(0, -1) + ' lazy-load>' }) count = (result.match(/lazy-load/g) || []).length - (src.match(/lazy-load/g) || []).length if (count > 0) { fs.writeFileSync(filePath, result, 'utf8') } return { changed: count > 0, count } } function walk(dir, out = []) { for (const name of fs.readdirSync(dir)) { if (EXCLUDE_DIRS.has(name)) continue const p = path.join(dir, name) const st = fs.statSync(p) if (st.isDirectory()) walk(p, out) else if (name.endsWith('.vue')) out.push(p) } return out } function main() { const allFiles = walk(ROOT) const targets = allFiles.filter(f => { const rel = path.relative(ROOT, f).split(path.sep).join('/') return TARGET_PATTERNS.some(p => rel.startsWith(p)) }) let grandTotal = 0 const log = [] for (const f of targets) { const rel = path.relative(ROOT, f) const r = processFile(f) if (r.changed) { grandTotal += r.count log.push(`${r.count.toString().padStart(3)} ${rel}`) } } console.log(`\n=== E 批 lazy-load 补全完成 ===`) console.log(`新增 lazy-load: ${grandTotal} 处`) log.sort((a, b) => parseInt(b.split(' ')[0]) - parseInt(a.split(' ')[0])) for (const line of log.slice(0, 30)) console.log(line) } main()