CSS削除の前後でレイアウト崩れがないかどうかチェックするスクリプトを書いた
はじめに
「よっしゃあ、サイト高速化するぞ!」
「むむ、CSSサイズが大きいなぁ。軽量化しよう!」
「このCSS使われてないやん、、削除ー!」
・・・・・
他のページのレイアウト崩れてるやん 😇
CSSの構造が複雑になっていたので、削除の影響範囲わかんない。どうしよう。
ってことで、対応の前後でレイアウト崩れがないかどうかをチェックできるスクリプトをつくりました。
あんましnode使ったことなかったんですが、puppeteerでさくっと作れました。
流れとしては、
- 対応の前後でサイトのスクショを撮る
- スクショ画像の差分をチェックする
っていう手順です。
サイトのスクショを撮る
PATHS
にスクショ撮影対象のパスを入れてます。
スマホサイトにするためにUserAgentも設定。
ディレクトリつくってそこに一括で画像保存してます。
// main.js // iPhone X に合わせた const DEFAULT_VIEWPORT = { width: 375, height: 812, deviceScaleFactor: 1, }; const puppeteer = require('puppeteer'); const fs = require('fs'); const DEFAULT_HOST = 'https://qiita.com'; const PATHS = [ '/', '/paranishian', '/tags/aws', '/tags/ruby' ] const date = new Date(); const timestamp = date.getTime().toString(); async function run(){ // ブラウザを起動する const browser = await puppeteer.launch({ // headless: false, defaultViewport: DEFAULT_VIEWPORT, }); // ページつくる const context = await browser.createIncognitoBrowserContext(); const page = await context.newPage(); // スマホのUserAgentにする await page.setUserAgent('Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.96 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)') // ディレクトリ作成 fs.mkdirSync(timestamp); for(const path of PATHS) { const url = DEFAULT_HOST + path; await page.goto(url, {waitUntil: 'networkidle2'}); console.log(`Done! : ${url}`); const filename = path.replace(/\//g, '_') + '.png'; // スクリーンショットを保存 await page.screenshot({path: timestamp + '/' + filename, fullPage: true}) } // 終了 await browser.close() } run()
さっそく実行。
❯ node main Done! : https://qiita.com/ Done! : https://qiita.com/paranishian Done! : https://qiita.com/tags/aws Done! : https://qiita.com/tags/ruby ❯ ls -l 1542803191786 total 12144 -rw-r--r-- 1 paranishian www 657027 11 21 21:26 _.png -rw-r--r-- 1 paranishian www 749702 11 21 21:26 _paranishian.png -rw-r--r-- 1 paranishian www 2202719 11 21 21:26 _tags_aws.png -rw-r--r-- 1 paranishian www 2599285 11 21 21:26 _tags_ruby.png
こんな感じで画像保存してます。
差分をチェックする
pixel-diff
で差分をチェックします。
// diff.js const DIFF_DIRECTORY = 'diff'; const fs = require('fs'); const PixelDiff = require('pixel-diff'); const PNG = require('pngjs').PNG; const path = require('path'); const argv = require('yargs') .options({ 'a': { describe: '比較対象画像のディレクトリA', type: 'string', demandOption: true }, 'b': { describe: '比較対象画像のディレクトリB', type: 'string', demandOption: true }, }) .help() .argv; async function checkDiff(filename) { // NOTE: 同じファイル名の画像がある前提なのでファイルの存在チェックはしていない const imageA = `${argv.a}/${filename}`; const imageB = `${argv.b}/${filename}`; const pngA = await PNG.sync.read(fs.readFileSync(imageA)); const diff = new PixelDiff({ imageAPath: imageA, imageBPath: imageB, thresholdType: PixelDiff.THRESHOLD_PERCENT, // thresholdType: PixelDiff.RESULT_DIFFERENT, threshold: 0.01, // 1% threshold imageOutputPath: `${DIFF_DIRECTORY}/${filename}`, cropImageB: { x: 0, y: 0, width: pngA.width, height: pngA.height, }, }); const result = await diff.runWithPromise(); console.log(`Found ${result.differences} pixels differences in ${filename}.`); } async function run(){ // diff保存用ディレクトリ作成 if (!fs.existsSync(DIFF_DIRECTORY)){ fs.mkdirSync(DIFF_DIRECTORY); } if (!fs.existsSync(argv.a) || !fs.existsSync(argv.b)){ throw new Error('ディレクトリが見つかりません!'); } fs.readdir(argv.a, (err, files) => { files.forEach(file => { // pngファイル以外は無視する if(path.extname(file) != '.png') { return; } checkDiff(file) }); }) } run()
引数に対象ディレクトリ名を指定して実行すると、diffディレクトリが作成されて差分画像が保存されます。
❯ node diff -a 12345 -b 67890 ...
最終的にはCIに導入してmasterとの差分チェックを自動化するのが目標です。
それにしてもpuppeteerは簡単で最高ですね 🤤
どなたかの参考になれば幸いです 🤗