UNPKG

lhci-collect

Version:

155 lines 6.21 kB
#!/usr/bin/env node import { Command } from 'commander'; import got from 'got'; import { XMLParser } from 'fast-xml-parser'; import { writeFileSync, readFileSync, existsSync } from 'fs'; import { stringify as yamlStringify } from 'yaml'; export const program = new Command(); program .name('collect') .description('Generate Lighthouse CI configuration from sitemap URLs') .requiredOption('-u, --sitemap-url <urls...>', 'One or more sitemap URLs (supports http/https URLs or local file paths)') .option('-f, --format <format>', 'Output format (json, yaml, js)', 'json') .option('-o, --output <file>', 'Output file path (default: stdout)') .option('-r, --runs <number>', 'Number of Lighthouse runs per URL', '1') .option('-s, --start-cmd <cmd>', 'Start server command example: pnpm start,default no start server') .option('--preset <preset>', 'Lighthouse preset', 'desktop') .option('--upload-url <url>', 'LHCI server base URL', 'http://localhost:9001') .option('--upload-token <token>', 'LHCI token') .option('--assert-preset <preset>', 'Assert preset', 'lighthouse:all') .option('--chrome-flags <flags>', 'Chrome flags for Lighthouse: --no-sandbox --headless --disable-gpu --disable-dev-shm-usage,default: --no-sandbox --headless --disable-gpu', '--no-sandbox --headless --disable-gpu') .action(main); const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: '@_', }); async function fetchSitemapUrls(url) { try { let xmlData; // 检查是否是本地文件路径 if (url.startsWith('file://')) { const filePath = url.replace('file://', ''); if (!existsSync(filePath)) { throw new Error(`Local file not found: ${filePath}`); } xmlData = readFileSync(filePath, 'utf-8'); } else if (url.startsWith('/') || url.startsWith('./') || url.startsWith('../')) { // 相对或绝对本地路径 if (!existsSync(url)) { throw new Error(`Local file not found: ${url}`); } xmlData = readFileSync(url, 'utf-8'); } else { // HTTP/HTTPS URL const res = await got(url); xmlData = res.body; } const json = parser.parse(xmlData); // sitemap index: <sitemapindex><sitemap><loc>...</loc></sitemap></sitemapindex> if (json.sitemapindex && json.sitemapindex.sitemap) { const sitemaps = json.sitemapindex.sitemap; const list = Array.isArray(sitemaps) ? sitemaps : [sitemaps]; // 递归获取所有子 sitemap URLs const results = await Promise.all(list.map((sm) => fetchSitemapUrls(sm.loc))); return results.flat(); } // urlset: <urlset><url><loc>...</loc></url></urlset> if (json.urlset && json.urlset.url) { const urls = json.urlset.url; const list = Array.isArray(urls) ? urls : [urls]; return list.map((u) => u.loc).filter(Boolean); } console.warn(`Warning: Unrecognized sitemap format at ${url}`); return []; } catch (e) { console.error(`Failed to fetch or parse sitemap ${url}: ${e.message}`); return []; } } function formatConfig(config, format) { switch (format.toLowerCase()) { case 'yaml': case 'yml': return yamlStringify(config); case 'js': return `module.exports = ${JSON.stringify(config, null, 2)};`; case 'json': default: return JSON.stringify(config, null, 2); } } function getDefaultFileName(format) { switch (format.toLowerCase()) { case 'yaml': return 'lighthouserc.yaml'; case 'yml': return 'lighthouserc.yml'; case 'js': return 'lighthouserc.js'; case 'json': default: return 'lighthouserc.json'; } } async function main(options) { const sitemapUrls = options.sitemapUrl; console.log(`🔍 Fetching URLs from ${sitemapUrls.length} sitemap(s)...`); // 收集所有 urls let allUrls = []; for (const sitemapUrl of sitemapUrls) { console.log(`📄 Processing sitemap: ${sitemapUrl}`); const urls = await fetchSitemapUrls(sitemapUrl); console.log(` Found ${urls.length} URLs`); allUrls = allUrls.concat(urls); } // 去重 const uniqueUrls = [...new Set(allUrls)]; console.log(`✨ Total unique URLs: ${uniqueUrls.length} (removed ${allUrls.length - uniqueUrls.length} duplicates)`); if (uniqueUrls.length === 0) { console.error('❌ No URLs found in sitemaps'); process.exit(1); } // 生成 LHCI 配置 const collectConfig = { url: uniqueUrls, numberOfRuns: Number(options.runs), settings: { preset: options.preset, chromeFlags: options.chromeFlags, }, }; // 只有当用户明确提供了 startCmd 参数时,才添加 startServerCommand if (options.startCmd) { collectConfig.startServerCommand = options.startCmd; } const config = { ci: { assert: { preset: options.assertPreset }, upload: { target: 'lhci', serverBaseUrl: options.uploadUrl, token: options.uploadToken, }, collect: collectConfig, }, }; // 格式化配置 const formattedConfig = formatConfig(config, options.format); // 输出到文件或控制台 if (options.output) { writeFileSync(options.output, formattedConfig); console.log(`✅ Configuration saved to: ${options.output}`); } else { // 如果没有指定输出文件,输出到控制台 console.log('\n📋 Generated Lighthouse CI configuration:\n'); console.log(formattedConfig); // 提示用户可以保存到默认文件 const defaultFileName = getDefaultFileName(options.format); console.log(`\n💡 Tip: You can save this to ${defaultFileName} using the -o option`); } } //# sourceMappingURL=index.js.map