Skip to content

Instantly share code, notes, and snippets.

@pirosikick
Last active November 17, 2019 08:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pirosikick/45ec70cc625b0fce8e66546d9dda4b8f to your computer and use it in GitHub Desktop.
Save pirosikick/45ec70cc625b0fce8e66546d9dda4b8f to your computer and use it in GitHub Desktop.
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;
@n-makoto
Copy link

こんにちは。貴記事を拝見してスマートなアプローチに痺れたので真似させていただいているところです。ありがとうございます。
ところで、39行目の startIndex => range.end の部分は数値の比較をする意図かと思いますが、アロー関数のシンタックスに適合してしまうため startIndex >= range.end とするべきところかと見受けました。
こちら合っていますでしょうか?
本来プルリクを出すべきところですがgistのためコメントにて失礼します。

@pirosikick
Copy link
Author

@mkt0225 ご指摘ありがとうございます。おっしゃる通りでしたので、修正しました!

@n-makoto
Copy link

@pirosikick 素早いご対応ありがとうございます!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment