Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 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;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement