Last active
November 17, 2019 08:31
-
-
Save pirosikick/45ec70cc625b0fce8e66546d9dda4b8f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const postcss = require("postcss"); | |
// 行番号・列番号をソースコード上の位置(0 〜 ソースコード.length - 1)に変換 | |
const lineColumnToIndex = (coverage, line, column) => { | |
// 各行の改行文字を含む文字数 | |
const countPerLine = coverage.text.split("\n").map((lineStr, index, lines) => | |
// 最終行以外は改行文字分の+1をする | |
index === lines.length - 1 ? lineStr.length : lineStr.length + 1 | |
); | |
// 配列の要素を全て足す関数 | |
const sum = arr => arr.reduce((acc, val) => acc + val, 0); | |
// 1~${line - 1}行まで文字数 + column = ソースコード上の位置 | |
return sum(countPerLine.slice(0, line)) + column - 1; | |
}; | |
// ノードが削除対象か判定 | |
const isNodeUnneeded = (node, coverage) => { | |
// Root, Comment, Declarationは削除しない | |
if (["root", "comment", "decl"].includes(node.type)) { | |
return false; | |
} | |
// @font-faceは削除しない | |
if (node.type === "atrule" && node.name === "font-face") { | |
return false; | |
} | |
// その他:カバレッジが無ければ削除 | |
// ノードのソース上での開始・終了位置(行列番号) | |
const { start, end } = node.source; | |
// 行列番号を文字列位置(0 ~ ソースコード文字列.length - 1)に変換 | |
const startIndex = lineColumnToIndex(coverage, start.line, start.column); | |
const endIndex = lineColumnToIndex(coverage, end.line, end.column); | |
// ノードのソースコード上の範囲を含むカバレッジを探す | |
const covered = coverage.ranges.find( | |
range => !(startIndex >= range.end || endIndex < range.start) | |
); | |
// カバレッジが見つかれなければ、trueを返す | |
return typeof covered === "undefined"; | |
}; | |
/** | |
* PuppeteerのCSSカバレッジから不要なスタイルを削除したCSSを生成 | |
* | |
* @param {Object} coverage - stopCSSCoverageが返す配列の要素 | |
*/ | |
const removeUnusedCSS = coverage => { | |
// CSSからASTを生成 | |
const root = postcss.parse(coverage.text); | |
// ASTの探索 | |
root.walk(node => { | |
// 削除対象か? | |
if (isNodeUnneeded(node, coverage)) { | |
// 削除対象ならASTから削除する | |
node.remove(); | |
} | |
}); | |
// ASTからCSSを生成 | |
return root.toString(); | |
}; | |
module.exports = removeUnusedCSS; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
こんにちは。貴記事を拝見してスマートなアプローチに痺れたので真似させていただいているところです。ありがとうございます。
ところで、39行目の
startIndex => range.end
の部分は数値の比較をする意図かと思いますが、アロー関数のシンタックスに適合してしまうためstartIndex >= range.end
とするべきところかと見受けました。こちら合っていますでしょうか?
本来プルリクを出すべきところですがgistのためコメントにて失礼します。