全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2021-11-02_如何编写属于自己的PostCSS 8插件?

您的位置:首页 >> 新闻 >> 行业资讯

如何编写属于自己的PostCSS 8插件? 作者 | 李佳浩 笔者近期在将前端架构 webpack 升级到 5 时,一些配套模块也需要进行升级,其中包括了 css 处理模块 PostCSS。旧版本使用的是 PostCSS 7,在升级至 PostCSS 8 的过程中,笔者发现部分插件前置依赖还是停留在 7 版本,且年久失修,在 PostCSS 8 中出现各种各样的问题,无奈只能研究源码,将目前部分旧版本插件升级至新版本。这里,笔者将升级插件的过程进行简化和提炼,让读者自己也可以编写一个 PostCSS 8 插件。 插件工作原理 PostCSS 是一个允许使用 JS 插件转换样式的工具。开发者可以根据自己的实际需求,在编译过程将指定 css 样式进行转换和处理。目前 PostCSS 官方收录插件有 200 多款,其中包括使用最广泛的Autoprefixer自动补全 css 前缀插件。 PostCSS 和插件的工作原理其实很简单,就是先将 css 源码转换为 AST,插件基于转换后 AST 的信息进行个性化处理,最后 PostCSS 再将处理后的 AST 信息转换为 css 源码,完成 css 样式转换,其流程可以归结为下图: 下面我们通过实际例子看看 PostCSS 会将 css 源码转换成的 AST 格式: const postcss = require('postcss') postcss().process(` .demo { font-size: 14px; /*this is a comment*/ } `).then(result = { console.log(result) }) 代码中直接引用 PostCSS,在不经过任何插件的情况下将 css 源码进行转换,AST 转换结果如下: { "processor": { "version": "8.3.6", "plugins": [] }, "messages": [], "root": { "raws": { "semicolon": false, "after": "\n" }, "type": "root", // ↓ nodes 字段内容重点关注 "nodes": [ { "raws": { "before": "\n", "between": " ", "semicolon": true, "after": "\n" }, "type": "rule", "nodes": [ { "raws": { "before": "\n ", "between": ": " }, "type": "decl", "source": { "inputId": 0, "start": { "offset": 11, "line": 3, "column": 3 }, "end": { "offset": 26, "line": 3, "column": 18 } }, "prop": "font-size", // css 属性和值 "value": "14px" }, { "raws": { "before": " ", "left": "", "right": "" }, "type": "comment", // 注释类 "source": { "inputId": 0, "start": { "offset": 28, "line": 3, "column": 20 }, "end": { "offset": 48, "line": 3, "column": 40 } }, "text": "this is a comment" } ], "source": { "inputId": 0, "start": { "offset": 1, "line": 2, "column": 1 }, "end": { "offset": 28, "line": 4, "column": 1 } }, "selector": ".demo", // 类名 "lastEach": 1, "indexes": {} } ], "source": { "inputId": 0, "start": { "offset": 0, "line": 1, "column": 1 } }, "lastEach": 1, "indexes": {}, "inputs": [ { "hasBOM": false, "css": "\n.demo {\n font-size: 14px;\n}\n", "id": "input css vi1Oew" } ] }, "opts": {}, "css": "\n.demo {\n font-size: 14px;\n}\n" } AST 对象中 nodes 字段里的内容尤为重要,其中存储了 css 源码的关键字、注释、源码的起始、结束位置以及 css 的属性和属性值,类名使用selector存储,每个类下又存储一个 nodes 数组,该数组下存放的就是该类的属性 (prop) 和属性值 (value)。那么插件就可以基于 AST 字段对 css 属性进行修改,从而实现 css 的转换。 PostCSS 插件格式规范及 API PostCSS 插件其实就是一个 JS 对象,其基本形式和解析如下: module.exports = (opts = { }) = { // 此处可对插件配置 opts 进行处理 return { postcssPlugin: 'postcss-test', // 插件名字,以 postcss- 开头 Once (root, postcss) { // 此处 root 即为转换后的 AST,此方法转换一次 css 将调用一次 }, Declaration (decl, postcss) { // postcss 遍历 css 样式时调用,在这里可以快速获得 type 为 decl 的节点 (请参考第二节的 AST 对象) }, Declaration: { color(decl, postcss) { // 可以进一步获得 decl 节点指定的属性值,这里是获得属性为 color 的值 } }, Comment (comment, postcss) { // 可以快速访问 AST 注释节点(type 为 comment) }, AtRule(atRule, postcss) { // 可以快速访问 css 如 @media,@import 等 @定义的节点(type 为 atRule) } } } module.exports.postcss = true 更多的 PostCSS 插件 API 可以详细参考官方 PostCSS 8 文档 (https://postcss.org/api/),基本原理就是 PostCSS 会遍历每一个 css 样式属性值、注释等节点,之后开发者就可以针对个性需求对节点进行处理即可。 实际开发一个 PostCSS 8 插件 了解了 PostCSS 插件的格式和 API,我们将根据实际需求来开发一个简易的插件,有如下 css: .demo { font-size: 14px; /*this is a comment*/ color: #ffffff; } 需求如下: 删除 css 内注释 将所有颜色为十六进制的#ffffff转为 css 内置的颜色变量white 根据第三节的插件格式,本次开发只需使用Comment和Declaration接口即可: // plugin.js module.exports = (opts = { }) = { return { postcssPlugin: 'postcss-test', Declaration (decl, postcss) { if (decl.value === '#ffffff') { decl.value = 'white' } }, Comment(comment) { comment.text = '' } } } module.exports.postcss = true 在 PostCSS 中使用该插件: // index.js const plugin = require('./plugin.js') postcss([plugin]).process(` .demo { font-size: 14px; /*this is a comment*/ color: #ffffff; } `).then(result = { console.log(result.css) }) 运行结果如下: .demo { font-size: 14px; /**/ color: white; } 可以看到,字体颜色值已经成功做了转换,注释内容已经删掉,但注释标识符还依旧存在,这是因为注释节点是包含/**/内容存在的,只要 AST 里注释节点还存在,最后 PostCSS 还原 AST 时还是会把这段内容还原,要做到彻底删掉注释,需要对 AST 的 nodes 字段进行遍历,将 type 为 comment 的节点进行删除,插件源码修改如下: // plugin.js module.exports = (opts = { }) = { // Work with options here // https://postcss.org/api/#plugin return { postcssPlugin: 'postcss-test', Once (root, postcss) { // Transform CSS AST here root.nodes.forEach(node = { if (node.type === 'rule') { node.nodes.forEach((n, i) = { if (n.type === 'comment') { node.nodes.splice(i, 1) } }) } }) }, Declaration (decl, postcss) { // The faster way to find Declaration node if (decl.value === '#ffffff') { decl.value = 'white' } } } } module.exports.postcss = true 重新执行 PostCSS,结果如下,符合预期。 .demo { font-size: 14px; color: white; } 插件开发注意事项 通过实操开发可以看到,开发一个 PostCSS 插件其实很简单,但在实际的插件开发中,开发者需要注意以下事项: 1. 尽量使插件简单,使用者可以到手即用 Build code that is short, simple, clear, and modular. 尽量使你的插件和使用者代码解耦,开放有限的 API,同时开发者在使用你的插件时从名字就可以知道插件的功能。这里推荐一个简单而优雅的 PostCSS 插件 postcss-focus(https://github.com/postcss/postcss-focus),读者可以从这个插件的源码中体会这个设计理念。 2. 开发插件前确认是否有现成的轮子 如果你对自己的项目有个新点子,想自己开发一个插件去实现,在开始写代码前,可以先到 PostCSS 官方注册的插件列表 (https://github.com/postcss/postcss/blob/main/docs/plugins.md) 中查看是否有符合自己需求的插件,避免重复造轮子。不过截止目前 (2021.8),大部分插件依旧停留在 PostCSS 8 以下,虽然 PostCSS 8 已经对旧版本插件做了处理,但在 AST 的解析处理上还是有差异,从实际使用过程中我就发现 PostCss8 使用低版本插件会导致 AST 内的 source map 丢失 (https://github.com/leodido/postcss-clean/issues/17),因此目前而言完全兼容 PostCSS 8 的插件还需各位开发者去升级。 从低版本 PostCSS 迁移 升级你的 PostCSS 插件具体可以参考官方给出的 升级指引。这里只对部分关键部分做下解释: 1. 升级 API将旧版module.exports = postcss.plugin(name, creator)替换为module.exports = creator; 新版插件将直接返回一个对象,对象内包含Once方法回调; 将原插件逻辑代码转移至Once方法内; 插件源码最后加上module.exports.postcss = true; 具体示例如下。 旧版插件: - module.exports = postcss.plugin('postcss-dark-theme-class', (opts = {}) = { - checkOpts(opts) - return (root, result) = { root.walkAtRules(atrule = { … }) - } - }) 升级后插件: + module.exports = (opts = {}) = { + checkOpts(opts) + return { + postcssPlugin: 'postcss-dark-theme-class', + Once (root, { result }) { root.walkAtRules(atrule = { … }) + } + } + } + module.exports.postcss = true 2. 提取逻辑代码至新版 API把逻辑代码都放在Once回调内还不够优雅,PostCSS 8 已经实现了单个 css 的代码扫描,提供了Declaration(), Rule(), AtRule(), Comment()等方法,旧版插件类似root.walkAtRules的方法就可以分别进行重构,插件效率也会得到提升: module.exports = { postcssPlugin: 'postcss-dark-theme-class', - Once (root) { - root.walkAtRules(atRule = { - // Slow - }) - } + AtRule (atRule) { + // Faster + } } module.exports.postcss = true 总 结 通过本文的介绍,读者可以了解 PostCSS 8 工作的基本原理,根据具体需求快速开发一个 PostCSS 8 插件,并在最后引用官方示例中介绍了如何快速升级旧版 PostCSS 插件。目前 PostCSS 8 还有大量还没进行升级兼容的 PostCSS 插件,希望读者可以在阅读本文后可以获得启发,对 PostCSS 8 的插件生态做出贡献。 你也「在看」吗???

上一篇:2018-12-17_给你90分钟,你能否拉低深度学习的入门门槛? 下一篇:2020-08-06_「转」特斯拉自动驾驶再酿车祸,年卖百亿的智能软件到底靠不靠谱?

TAG标签:

14
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价