Skip to content

css-diff #48

@webfansplz

Description

@webfansplz

Repository (仓库地址) : css-diff

Gain (收获) : css-diff 是一个对比 css 差异的库,使用它可以对比两个 css 文件的差异。收获见以下源码解析~

// a.css

.a {
  font-size: 16px;
  color: #fff;
}

// b.css

.a {
  font-size: 16px;
  color: #fff;
}

.b {
  font-weight: normal;
}
// index.js

require("css-diff")({
  files: ["./a.css", "./b.css"],
  omit: ["comment"],
  visual: true,
}).then(function (diff) {
  console.log(diff.visual); // 见下图
  console.log(diff.different); // ture
});

css-diff

源码解析

require("colors");

var cssParse = require("css-parse");
var Promise = require("bluebird");
var Diff = require("diff");
var Compiler = require("./lib/compiler.js");
var Path = require("path");

module.exports = function (options) {
  this.options = options;

  return (
    getContents
      .call(this, options.files)
      // 将两个css文件的cssom 传递给Diff.diffLines方法进行对比
      .spread(Diff.diffLines)
      // 生成差异
      .then(generateDiff)
      .catch(handleError)
  );
};

function handleError(e) {
  process.stderr.write(("Error: " + e.message + "\n").red.inverse);
  process.exit(1);
}
// 核心实现
function generateDiff(diff) {
  var different = false;
  var visual = diff.reduce(function (prev, part) {
    // 判断block是否有差异,很骚的双三元判断
    /**
     * 新增区域使用绿色渲染差异
     * 移除区域使用红色渲染差异
     * 灰色代表相同部分
     * 总结: 灰色表示相同的部分,绿色表示多出来的部分,红色表示少了的部分.
     */
    var color = part.added ? "green" : part.removed ? "red" : "grey";
    // 灰色,表示两个文件不存在差异
    if (color !== "grey") {
      different = true;
    }

    return prev + part.value[color] + "\n";
  }, "");

  return {
    different: different,
    visual: visual,
  };
}

function getContents(files) {
  var _this = this;

  if (files.length < 2) {
    return new Error("you must pass 2 file paths in");
  }

  return Promise.all(
    files.map(function (path) {
      return Compiler(Path.resolve(path)).then(function (css) {
        // 获取css字符串,使用cssParse将css字符串转换为CSSOM
        // css string -> cssom
        var rules = cssParse(css).stylesheet.rules; // 输出结果可见下图
        // 返回 序列化后的 过滤omit参数选项的cssom规则类型数组
        // 这里有个小技巧,JSON.stringify使用了space参数,用于在输出JSON字符串中插入空格以提高可读性。
        return JSON.stringify(
          rules.filter(function (rule) {
            return !~_this.options.omit.indexOf(rule.type);
          }),
          null,
          4
        );
      });
    })
  );
}

a.css,b.css cssom rules output

rules

思考

// 以下代码,你觉得输出的会是什么呢?

require("css-diff")({
  files: ["./b.css", "./a.css"],
  omit: ["comment"],
  visual: true,
}).then(function (diff) {
  console.log(diff.visual);
  console.log(diff.different);
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions