postcss开发实战

初识postcss

css是web开发中重要的一部分,然而css规范仍存在一些浏览器兼容性问题,由此出现了sass、less、stylus等css预处理器,提升了开发人员的效率。javascript

postcss的官方定义:css

A tool for transforming CSS with JavaScript前端

一个用javascript来处理css语法的工具。postcss自己不会对css文件进行修改,它只将css文件转化为抽象语法树(abstract syntax tree,后简称ast),而后插件对语法树进行处理,最后由postcss将ast还原为普通css,因此postcss对css文件的修改都是基于插件来实现的。java

postcss能够作什么

截止到目前,postcss已有200多个插件,列举一些比较出名的插件node

  1. autoprefixerwebpack

    它从caniuse网站上的数据,自动添加浏览器前缀到css中,帮助开发人员解决浏览器兼容问题。git

  2. postcss-preset-envgithub

    支持css的最新特性,并兼容大多数浏览器。web

  3. postcss-modulesshell

    模块化css代码,为选择器提供命名空间后缀。

  4. precss

    解析一些类sass语法,包括:变量、嵌套、mixins等。

  5. stylelint

    css语法检查器,能够帮助开发者检查css文件中的语法错误。

更多插件地址:github.com/postcss/pos…

postcss用法

postcss能够与各类前端打包工具相结合使用,例如webpack、gulp、grunt、rollup...

webpack

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'style-loader',
          },
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
            }
          },
          {
            loader: 'postcss-loader'
          }
        ]
      }
    ]
  }
}
// postcss.config.js
module.exports = {
  plugins: [
    require('precss'),
    require('autoprefixer')
  ]
}
复制代码

也能够直接使用postcss提供的js api直接处理css。

JS API

const autoprefixer = require('autoprefixer')
const postcss = require('postcss')
const precss = require('precss')
const css = ` .test { color: #fff; } `;

postcss([precss, autoprefixer])
    .process(css, { from: 'src/app.css', to: 'dest/app.css' })
    .then(result => {
    	console.log(result.css);
	});
复制代码

从零开始开发一个postcss插件

抽象语法树

开发postcss插件前,首先要理解的一个概念就是文章开头提到的抽象语法树,postcss将css文本转化为ast,javascript能够经过一系列api来操做、改变ast,再由解析器将ast解析成普通目标css文本。

css文件:

body {
    margin: 0;
}
复制代码

转化为ast,对应的json:

{
  "raws": {
    "semicolon": false,
    "after": ""
  },
  "type": "root",
  "nodes": [
    {
      "raws": {
        "before": "",
        "between": " ",
        "semicolon": true,
        "after": "\n"
      },
      "type": "rule",
      "nodes": [
        {
          "raws": {
            "before": "\n\t",
            "between": ": "
          },
          "type": "decl",
          "source": {
            "start": {
              "line": 2,
              "column": 2
            },
            "input": {
              "css": "body {\n\tmargin: 0;\n}",
              "id": "<input css 32>"
            },
            "end": {
              "line": 2,
              "column": 11
            }
          },
          "prop": "margin",
          "value": "0"
        }
      ],
      "source": {
        "start": {
          "line": 1,
          "column": 1
        },
        "input": {
          "css": "body {\n\tmargin: 0;\n}",
          "id": "<input css 32>"
        },
        "end": {
          "line": 3,
          "column": 1
        }
      },
      "selector": "body"
    }
  ],
  "source": {
    "input": {
      "css": "body {\n\tmargin: 0;\n}",
      "id": "<input css 32>"
    },
    "start": {
      "line": 1,
      "column": 1
    }
  }
}
复制代码

其中,ast的第一级是一个root类型的节点,type除root外还包括rule、decl、atrule、comment,nodes属性表示节点下的子节点。

postcss为咱们提供了一些基本的ast操做方法:

  • walk:遍历全部节点信息
  • walkAtRules:遍历全部atrule类型节点
  • walkRules:遍历全部rule类型节点
  • walkComments:遍历全部comment类型节点

更多节点信息参照postcss api文档:api.postcss.org/

插件开发

咱们开发一个将像素值乘以2的插件。

const postcss = require('postcss');

const postcssPluginParseMargin = postcss.plugin('postcss-parse-margin', function(){
	return function(root){
		root.walkDecls(function(decl){
			decl.value = decl.value.replace(/(\d*\.?\d+)\s*px/, function(match, numStr) {
				return Number(numStr) * 2 + 'px';
			});
		});
	}
});
const css = ` .test { font-size: 2.5px; } `;
postcss([postcssPluginParseMargin]).process(css).then(function(res){
	console.log(res.css); 
});
/** .test { font-size: 5px; } */

复制代码

咱们调用walkDecls函数,从root节点开始遍历全部的decl类型节点,取出decl.value中的像素值,乘以2后替换掉原有decl.value,这样就实现了一个简单的postcss插件。

实际问题:postcss转义less语法

less是一种css预处理器,为css扩展了更多的功能,如变量、继承、mixins、函数等。若是咱们想基于less的语法使用postcss的插件,一种方案是使用less将less语法转义成css语法后,再用postcss处理转义后的css文件,但这种方案因为要经历两次语法树的生成过程,比较耗时。与sass不一样,less自己就是js编写的,所以咱们能够基于less自带的语法树解析器,将less语法树直接转化为postcss语法树,就能够无缝衔接使用其余postcss插件。

这个轮子已经有大神帮咱们造好,叫作postcss-less-engin,只是项目已有一年多未更新,less仍是基于2.7.1版本,更新到3.0.0以上会报错。查阅了less的changelog,发现缘由是3.0.0之后,less解析器中的Directive类重命名为AtRule,Rule重命名为Declaration。bug修复好已提pr等待做者更新,你们若有须要支持最新less能够暂时使用postcss-less-engine-latest,git地址:github.com/Crunch/post…

插件用法:

const postcss = require('postcss');
const postCssLessEngine = require('postcss-less-engine');
const css = ` @color: red; .test { color: @color; } `;

postcss([
    postCssLessEngine()
]).process(
    css, {
        parser: postCssLessEngine.parser
    }
).then((result)=>{
    console.log(result.css);
    /** .test { color: red; } */
});

复制代码

若是只想支持less的部分特性,彻底能够本身编写postcss插件来支持,postcss-less插件能够用来识别less语法,为postcss抽象语法树添加less标识,可是不会转换原有代码,转换工做交给其余postcss插件来完成,你们有兴趣能够开发适合本身需求的插件。

git地址:github.com/shellscape/…

相关文章
相关标签/搜索