PostCSS 是解析器,它将 CSS 解析为对象树(AST)。然后插件改变了这棵树,最后PostCSS 从一个修改过的对象树生成一个新的 CSS 字符串。
PostCSS 不是一个预处理器,也不是一种添加语法糖的方式,它是一个用于创建 CSS 工具的框架,是一个用 JavaScript 插件来转换样式的工具。一个 PostCSS 插件是一个接收并且通常从 PostCSS 解析器转换 CSS AST 的函数。PostCSS 让任何有 JavaScript 经验的人都可以创建自己的插件。
编写适用于postcss7.x版本的插件语法:
// 需要导入postcss
const postcss = require('postcss');
module.exports = postcss.plugin('postcss-merge2', (opts = {}) => {
return (root, result) => {
root.walkRules(rule => {
...
})
}
})
插件开发者现在可以在postcss8.0中选择使用一个新的 API,这个 API 可以提高构建速度,并减少其工具的最终用户的依赖大小。
编写适用于postcss8.x的插件使用新的插件 API,不需要导入 PostCSS,会得到所有的类和方法作为函数的第二个参数:
- const { decl: Declaration } = require('postcss')
module.exports = {
postcssPlugin: 'postcss-example',
- Once (root) {
+ Once (root, { Declaration }) {
…
}
}
module.exports.postcss = true
完整示例:
// 不需要导入postcss
module.exports = (opts = {}) => {
return {
postcssPlugin: 'PLUGIN NAME',
Rule(rule, { Declaration }) {
},
Declaration (decl) {
}
}
}
module.exports.postcss = true
之前,每个插件的依赖关系中都有 PostCSS。这可能会导致在 node_modules 中有多个 PostCSS 副本的问题:
node_modules/
autoprefixer/
node_modules/
postcss/ ← 重复
stylelint/
node_modules/
postcss/ ← 重复
postcss-normalize/
node_modules/
postcss/ ← 重复
postcss8.0将确保在 node_modules 中只有一个 PostCSS 实例。操作步骤是:通过编辑 package.json 将 postcss8移动到 peerDependencies,这样可以控制最终用户的 node_ 模块的大小: 现在,所有插件都将使用相同版本的 postcss 作为依赖。
{
"dependencies": {
- "postcss": "^7.0.10"
},
"devDependencies": {
+ "postcss": "^8.0.0"
},
+ "peerDependencies": {
+ "postcss": "^8.0.0"
+ }
}
之前每一个 PostCSS 插件都在这棵树中穿行。通常一个插件只是寻找一些属性,但是它仍然需要扫描整个树。如果构建工具中有很多插件(或者你使用一个预设插件,里面有很多插件,比如 postcss-preset-env 或者 stylelint) ,大部分的处理时间都会花在插件上,一遍又一遍地遍历树。
// walkDecls方法将遍历整个树以查找所有声明节点
root.walkDecls(decl => {
if (decl.prop === 'will-change') {
decl.cloneBefore({ prop: 'backface-visibility', value: 'hidden' })
}
})
postcss8.0提供一个用于插件的访问者 API,在postcss8.0中所有插件都可以共享 CSS 树的单次扫描。 它使 CSS 处理速度提高了 20%。 要使用单次扫描,需要删除 root.walk* 调用并将代码移动到插件对象中的 Declaration()、Rule()、AtRule() 或 Comment() 方法。
module.exports = {
postcssPlugin: 'postcss-dark-theme-class',
- Once (root) {
- root.walkAtRules(atRule => {
- // Slow
- })
- }
+ AtRule (atRule) {
+ // Faster
+ }
}
module.exports.postcss = true
现在要编写一个postcss的插件,将css中一个选择器下分开书写的margin、padding等属性合并在一起,并需要将插件集成到现有的项目中去。
例如:
div {
margin-top: 10px;
margin-bottom: 10px;
margin-left: 10px;
margin-right: 10px;
/* 合并后 */
margin: 10px;
}
我首先创建了一个新的项目,安装postcss(安装时没有指定版本,它默认会安装最新版,当前postcss的最新版本是8.3.6),查阅资料写插件……写好之后可以正常运行。
但是把插件放到现有的项目中后就失效了,转换不成功。非常奇怪。
后来发现项目中使用的postcss是7.x版本,于是我尝试着将版本升到8,然后插件就可以正常运行了。
前边有介绍到编写postcss7.x的插件语法和postcss8.x的插件语法是不一样的。
如果是新手,要编写postcss插件,那么直接去 postcss官网或者postcss的GitHub仓库查资料,它默认会引导我们使用新的插件语法编写适用于postcss8.x的插件。但是,如果项目中的postcss版本是7.x,使用新语法编写的插件就可能有问题,出现下方错误,提示需要使用postcss的8版本
此时有两种解决方法
总结:为 postcss7.x创建的插件适用于 postcss8.x,但是为postcss8.x创建的插件不一定适用于postcss7.x。
前端学习交流QQ群:862748629 点我加入