UNPKG

bia

Version:

a tool for download git repository

236 lines (214 loc) 8.12 kB
const puppeteer = require('puppeteer') const fse = require('fs-extra') const path = require('path') const SKELETON_CONFIG = require('../../config/skeleton.json') /** * 查询 skeleton config 文件是否存在 */ const checkSkeletonFile = () => { return new Promise((resolve, reject) => { try { let file = path.resolve(process.cwd(), 'biaSkeleton/config.json') fse.exists(file, exists => { resolve(exists) }) } catch (err) { reject(err) } }) } /** * 创建 skeleton config.json 文件 */ const createSkeletonFile = (_config = {}) => { return new Promise((resolve, reject) => { try { let dist = path.resolve(process.cwd(), 'biaSkeleton') fse.ensureDirSync(dist) fse.outputFileSync(path.resolve(dist, 'config.json'), JSON.stringify(Object.assign(SKELETON_CONFIG, _config), null, 4)) resolve() } catch (err) { reject(err) } }) } /** * 读取配置文件信息 */ const readConfigFlile = () => { return new Promise((resolve, reject) => { try { fse.readJson(path.resolve(process.cwd(), 'biaSkeleton/config.json'), (err, obj) => { if (err) { console.log('some error in config.json, Check the file format') reject(err) } resolve(obj) }) } catch (err) { reject(err) } }) } /* * 启动puppeteer 生成骨架屏 */ const outputSkeleton = async (config) => { const browser = await puppeteer.launch({ headless: false }) const page = await browser.newPage() // 拦截请求 await page.setRequestInterception(true); page.on('request', interceptedRequest => { if (/\.png|\.jpg|\.jpeg|\.gif/.test(interceptedRequest.url())) { interceptedRequest.abort() } else { interceptedRequest.continue() } }) // 设置cookie config.cookies && config.cookies.forEach(item => { page.setCookie(item) }) await page.setUserAgent(config.viewport.userAgent) // 设置视窗 await page.setViewport({ width: config.viewport.width || 375, height: config.viewport.height || 812, deviceScaleFactor: config.viewport.dpr || 2, isMobile: true, }) // 打开链接 await page.goto(config.url, { waitUntil: 'networkidle2', }) await page.content() // 操作页面 await page.evaluate((config) => { // 处理图片为灰色背景的方法 const formatImage = (query) => { try { Array.from(document.body.querySelectorAll(query)).forEach(node => { node.hasAttribute('alt') && node.removeAttribute('alt') node.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' node.style.backgroundColor = config.options.skeletonColor || '#eee' node.style.backgroundImage = 'none' const rect = node.getBoundingClientRect() node.style.width = rect.width node.style.height = rect.height }) } catch (err) { console.log(err) // } } // 处理文字为灰色背景的方法 const formatText = (query) => { try { Array.from(document.body.querySelectorAll(query)).forEach(node => { if (node.innerText !== node.innerHTML) return false const comStyle = window.getComputedStyle(node) let { lineHeight, fontSize, paddingTop, paddingBottom, } = comStyle const height = node.offsetHeight let lineCount = (height - parseInt(paddingTop, 10) - parseInt(paddingBottom, 10)) / parseInt(lineHeight, 10) | 0 lineCount = lineCount - 1 < 0 ? 0 : lineCount - 1 let textHeightRatio = parseInt(fontSize, 10) / parseInt(lineHeight, 10) const innerWrapper = document.createElement('biaspan') innerWrapper.innerText = node.innerText Object.assign(innerWrapper.style, { backgroundImage: `linear-gradient( transparent ${(1 - textHeightRatio) / 2 * 100}%, ${config.options.skeletonColor || '#eee'} 0%, ${config.options.skeletonColor || '#eee'} ${((1 - textHeightRatio) / 2 + textHeightRatio) * 100}%, transparent 0%)`, backgroundOrigin: 'content-box', backgroundSize: `100% ${parseFloat(lineHeight) * lineCount}px`, backgroundClip: 'content-box', backgroundColor: (lineCount ? 'transparent' : config.options.skeletonColor || '#eee'), fontSize, color: 'transparent', backgroundRepeat: 'repeat-y', display: 'inline', }) node.innerHTML = '' node.appendChild(innerWrapper) }) } catch (err) { console.log(err) // } } // 隐藏伪元素 let style = document.createElement('style') document.head.appendChild(style) sheet = style.sheet sheet.insertRule('*::before { display: none; }', 0) sheet.insertRule('*::after { display: none; }', 0) // 设置页面背景色 document.body.style.background = config.options.bgColor || '#fff' // 隐藏部分元素 if (config.options && config.options.hide) { config.options.hide.forEach(node => { Array.from(document.body.querySelectorAll(node)).forEach(subNode => { subNode.style.display = 'none' subNode.style.visibility = 'hidden' }) }) } // 所有元素全部变成透明,过滤ignore的元素 let ignoreNodeList = [] if (config.options && config.options.ignore) { config.options.ignore.forEach(node => { console.log(node) ignoreNodeList = ignoreNodeList.concat(Array.from(document.body.querySelectorAll(node))) }) } Array.from(document.body.querySelectorAll('*')).forEach(node => { if (!ignoreNodeList.includes(node)) { node.style.color = 'transparent' node.style.backgroundColor = 'transparent' node.style.background = 'none' node.style.border = 'none' // 处理 input,textarea node.placeholder = '' node.value = '' } }) // 处理图片 formatImage('img') // 处理自定义图片 if (config.options && config.options.img) { config.options.img.forEach(subNode => { formatImage(subNode, config) }) } // 处理文案 formatText('span, p') // 处理自定义文案 if (config.options && config.options.text) { config.options.text.forEach(subNode => { formatText(subNode, config) }) } }, config) // 截图 const distFolder = path.resolve(process.cwd(), 'biaSkeleton/result') await fse.ensureDir(distFolder) await page.screenshot({ path: path.resolve(distFolder, 'skeleton.png') }) // await browser.close() // process.exit() } module.exports = { checkSkeletonFile, createSkeletonFile, readConfigFlile, outputSkeleton, }