瞅瞅Facebook是怎么保证CSS代码质量的

原文地址
本文从属于笔者的Web 前端入门与最佳实践php

在Facebook里,上千名工程师工做在不一样的产品线上,为全世界的用户提供可靠优质的服务,而咱们在代码质量管理方面也面临着独一无二的挑战。不只仅是由于咱们面对的是一个庞大的代码基库,还有日渐增长的各类各样的特性,有时候若是你想去重构提升某一个模块,每每会影响到其余不少模块。具体在CSS而言,咱们须要处理上千份不停变化的CSS文件。以前咱们着力于经过Code Review、代码样式规范以及重构等手段协同工做,而保障代码质量,可是仍是会有不少的错误悄悄从眼皮底下溜走,被提交进入到代码库里。咱们一直用自建的CSS Linter来检测基本的代码错误与保证一致的编码风格,尽管它基本上已经知足了咱们的目标,但仍是存在不少的问题,所以我也想在这篇文章里对如何保障CSS的代码质量进行一些讨论。css

Regex is not Enough:以前用的是正则匹配,不咋的啊

老的Linter主要是基于不少个正则表达式对CSS中的语法进行提取,大概是这个样子的:前端

preg_match_all(
 // This pattern matches [attr] selectors with no preceding selector.  
    '/\/\*.*?\*\/|\{[^}]*\}|\s(\[[^\]]+\])/s',
 $data,   
 $matches,   
 PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
 foreach ($matches as $match) {
   if (isset($match[1])) {
     raiseError(...);
   }

基本上一个检测规则就须要添加一个专门的匹配规则,很是很差维护,在性能上也有很大的问题。对于每一个规则俺们都须要遍历整个文件,性能差得很。node

Abstract Syntax Tree

受够了正则表达式,咱们想搞一个更好用的也是更细致的CSS解释器。CSS自己也是一门语言,老把它当作纯文本文件处理也很差,所以咱们打算用AST,即抽象语法树的方式构建一个解析器。这种新的处理方式在性能上面有个很不错的提高,譬如咱们的代码库中有这么一段CSS代码:git

{
  display: none:
  background-color: #8B1D3;
  padding: 10px,10px,0,0;
  opacity: 1.0f;
}

眼神好的估计才能看出这个代码片断中存在的问题,譬如某个属性名错了、十六进制的颜色代码写错的,分隔符写错了等等。浏览器才不会主动给你报错呢,这样开发者本身也就很难找到错误了。在具体实现上,咱们发现PostCSS 是个不错的工具,所以咱们选择了Stylelint做为咱们新的Linter工具,它是基于PostCSS构建的,很是的灵活,社区也不错。github

就像JavaScript中的Esprima以及ESLint同样,Stylelint提供了对于完整的AST的访问方式,可以让你根据不一样的状况更快速简单的访问具体的代码节点,譬如如今咱们的检测规则写成了这个样子:正则表达式

root.walkDecls(node => {
  if (node.prop === 'text-transform' && node.value === 'uppercase') {
    report({
      ...
    });
  }
});

咱们也能够传入一些基本的函数,譬如linear-gradient,就像这个样子:浏览器

// disallow things like linear-gradient(top, blue, green) w. incorrect first valueroot.walkDecls(node => {
  const parsedValue = styleParser(node.value);
  parsedValue.walk(valueNode => {
    if (valueNode.type === 'function' && valueNode.value === 'linear-gradient') {
      const firstValueInGradient = styleParser.stringify(valueNode.nodes[0]);
      if (disallowedFirstValuesInGradient.indexOf(firstValueInGradient) > -1) {
        report({
          ...
        });
      }
    }
  });
});

这样子写出来的检测规则可读性更好,也更好去理解与维护,而且这种方式不管是在怎样的CSS格式化的状况下,以及无论规则和声明放在哪边,都能正常地工做。框架

Custom rules:自定义规则

咱们默认使用了一些Stylelint内置的规则,譬如declaration-no-important,selector-no-universal, 以及 selector-class-pattern。如何添加自定义规则的方法能够参考built-in plugin mechanism,而咱们使用的譬如:ide

  • slow-css-properties 来告警一些性能较差的属性,譬如opacity或者box-shadow

  • filters-with-svg-files 来告警Edge中不支持SVG的过滤

  • use-variables来告警那些能够被内置的常量替换的一些变量

  • common-properties-whitelist 来检测是否有些误写的其实不存在的属性

  • mobile-flexbox 来检测一些不被老版本手机浏览器支持的属性

  • text-transform-uppercase 来告警 "text-transform: uppercase",这个在某些语言表现的不友好

咱们也贡献了部分规则 以及 ad插件itions 给Stylelint。

Automatic replacement:自动替换

咱们检测过程当中有一个重要的工做就是自动格式化,Linter会在发现某些问题的时候问你是否须要根据规则进行替换,这个功能会节约你大量的手动修改校订的时间。通常来讲,咱们提交代码以前都会审视下Linter报出的错误,而后去修复这些错误。惋惜的是Stylelint并无内嵌的自动格式化与修复机制,所以咱们重写了部分的Stylelint的规则来增长一个自动替换与修复的功能。

Test all the things

咱们老的Linter还有个问题就是没有单元测试,这点就好像代码上线前不进行单元测试同样不靠谱。咱们面对的多是任意格式的处理文本,所以咱们也要保证咱们的检测规则可以适用于真实有效的环境,这里咱们是选择了Jest这个测试框架,Stylelint对它的支持挺好的,而后大概一个单元测试是这个样子:

test.ok('div { background-image: linear-gradient( 0deg, blue, green 40%, red ); }', 
  'linear gradient with valid syntax');
test.notOk('a { background: linear-gradient(top, blue, green); }', 
  message, 
    'linear-gradient with invalid syntax');

What‘s next

换一个靠谱的CSS Linter工具只是保证高质量的CSS的代码的第一步,咱们还打算添加不少自定义的检测规则来捕获一些常见的错误,保证使用规定的最佳实践以及统一代码约定规范。咱们已经在JavaScript的校验中进行了这一工做。

另外对于React社区中存在的CSS-in-JS这种写法,对于CSS Linter也是个不小的挑战,如今的大部分的Linter都是着眼于处理传统的CSS文件,之后会添加对于JSX的处理规范吧。

相关文章
相关标签/搜索