Postcss自定义插件
AndreGeng opened this issue · 1 comments
AndreGeng commented
PostCSS是一个利用plugin来transform样式的工具.
PostCSS提供api, 用来分析/修改css文件的rule. plugin可以利用这个api来做很多有用的任务.
Architecture
总览
PostCSS和Sass/Less不一样它不是一种样式语言, 而是一个用来做css语法转换的工具.
工作流
- css source string -> AST
代码量比较大的情况下性能比较差. - 分成词法分析/解析两步(css sourcee string -> tokens -> AST)
PostCSS采用的是这种方式. csstree和babel-parser也是采用的这种方式. 它的优点在于性能以及代码复杂度的降低.
核心结构
Writing a PostCSS Plugin
First PostCSS Plugin
postcss官方提供了一个boilterplate, 我们可以通过它来创建一个postcss插件.
git clone https://github.com/postcss/postcss-plugin-boilerplate.git
node ./postcss-plugin-boilerplate/start // 运行start脚本来生成插件
start脚本会提问如下问题
AUTHOR_NAME: 'Your name: ',
AUTHOR_EMAIL: 'Your email: ',
GITHUB_NAME: 'GitHub username: ',
PLUGIN_NAME: 'Plugin name: postcss-',
PLUGIN_DESC: '\nFinish sentence with plugin description:\nPostCSS plugin ',
KEYWORDS: '\nFinish plugin keywords:\npostcss, css, postcss-plugin, '
并根据我们的回答生成相应的插件, 看下生成插件的index.js文件
var postcss = require('postcss');
module.exports = postcss.plugin('PLUGIN_NAME', function (opts) {
opts = opts || {};
// Work with options here
return function (root, result) {
// Transform CSS AST here
};
});
root就是postcss提供的ast树的根节点, 它提供了一些方法方便我们遍历css ast树. 具体api可以在postcss api查看, 比较常用的方法就是像下面这样
root.walkRules(function (rule) { // rule代表一个个css 声明块, e.g. ul {}
rule.walkDecls(/^background(?:-image)?$/, (decl) => { // decl代表, 声明块里一条条属性键值, e.g. margin: 10px
});
});
上面代码做的就是找到所有包含background或是background-image的css属性, 键值. 然后我们可以通过改变decl.value来进行我们需要的转化,
rule.walkDecls(/^background(?:-image)?$/, (decl) => {
const p = (async function () {
const match = b64Regex.exec(decl.value);
try {
const base64 = await convertFileToBase64(match[1].trim(), opts.basedir, opts.mime);
decl.value = decl.value.replace(opts.b64Regex, base64);
} catch (e) {
console.error(e);
}
})();
注意: 如果我们的转换过程是异步的, 我们需要在transform ast tree的function里, 返回一个promise对象
module.exports = postcss.plugin('postcss-base64', function (options) {
// Work with options here
return function (root) {
const promises = [];
// Transform CSS AST here
root.walkRules(function (rule) {
rule.walkDecls(/^background(?:-image)?$/, (decl) => {
const p = (async function () {
})();
promises.push(p);
});
});
return Promise.all(promises);
};
});
大概过程就是这样可以动手试下, 印象会比较深刻些..
其它工具:
postcss ast explorer
AndreGeng commented