本文已获得原作者(Andrey Sitnik)和 Evil Martians 授权许可进行翻译。原文介绍了如何把 PostCSS 插件给迁移到 PostCSS 8.0。
随着 8.0 版本的发布,PostCSS 也迎来了一次大版本的更新,该版本的代号被命名为“欧赛魔神”(President Ose)。经过这次更新之后,PostCSS 插件的作者可以有选择性地使用一新 API,该 API 能够提升构建速度以及减少插件用户安装依赖的体积。该指南旨在描述一些内容:作为一个插件开发者,为了能够“掏空”(make the most out of) 新 PostCSS,你所需要采取的一些步骤。
PostCSS,一个使用 JavaScript 来处理 CSS 的框架。在经历周下载量超过
25_000_000
之后,已经成为当代 web 开发领域里面最流行的前端工具之一。
至于为什么会有那么多代码库依赖 PostCSS,一是因为 PostCSS 有 webpack 或者 Rails 等类似大项目背书,二是 PostCSS 插件生态的加持。不得不说,PostCSS 插件的出现改变前端开发者撸 CSS 的方式。
在 PostCSS 里面配置简单的 JavaScript 规则,就可以实现任务自动化,比如 CSS 语法检查以及给 CSS 属性名加浏览器前缀,或者支持新的 CSS 写法,该 CSS 写法还未被当前的 web 标准所直接接纳。
如果你有开发或者维护 PostCSS 插件的经历,那这篇博文就非常适合你阅读。因为它在这里面罗列出插件开发者为了让插件适配 PostCSS 新版本所应该做的二三事。
可以去 github 上看一下有关于此次最新发布的完整描述,了解一下 PostCSS 8.0 还有哪些新特性,包括更好的 source map 支持以及极具弹性(resilient)的 CSS 解析。
先前的 PostCSS 版本对于插件来说,可谓是限制重重:
dependencies
下不同版本的 PostCSS。如果 npm 执行删除重复数据的操作失败,这会导致最终的 node_modules
文件夹臃肿不堪。postcss.decl()
)。混用不同版本的 PostCSS 所创建的抽象语法树节点,会导致 bug 难以定位。postcss
移到 peerDependencies
里面第一步很简单,只需要把 PostCSS 7.x 从 dependencies
里面移除,然后把 PostCSS 8.x 加到 devDependencies
里面。
npm uninstall postcss
npm install postcss --save-dev
接着,通过编辑 package.json
文件,把 PostCSS 8.x 加到 peerDependencies
里面:
"dependencies": {
- "postcss": "^7.0.10"
},
"devDependencies": {
+ "postcss": "^8.0.0"
},
+ "peerDependencies": {
+ "postcss": "^8.0.0"
+ }
}
这样会控制插件用户的 node_modules
体积:现在,所有插件都会使用相同版本的 postcss
作为依赖。
如果你的 dependencies
里面没有任何内容,可以随意删除 dependencies
:
- "dependencies": {
- }
"devDependencies": {
不要忘记在自己的插件文档里面更新安装指引相关内容:
- npm install --save-dev postcss-focus
+ npm install --save-dev postcss postcss-focus
用 module.exports = creator
代替 module.exports = postcss.plugin(name, creator)
。
返回一个对象,该对象里面包含 postcssPlugin
属性以及 Once
方法,postcssPlugin
属性值为插件名。
把之前的插件代码移到 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
不要忘记 module.exports.postcss = true
。它可以让 PostCSS 区分出插件用户调用插件的方式:require('plugin')
以及 require('plugin')(opts)
。
PostCSS 8.x 会对 CSS 树进行一次扫描。多个插件可以借用这次扫描结果来获取更好的性能。
为了使用这次扫描结果,你需要移除 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
对于声明以及 @ 规则(at-rules),你可以通过订阅特定的声明属性或者 @ 规则(at-rules) 名字来获取更快的代码执行速度:
module.exports = {
postcssPlugin: 'postcss-example',
- AtRule (atRule) {
- if (atRule.name === 'media') {
- // Faster
- }
- }
+ AtRule: {
+ media: atRule => {
+ // The fastest
+ }
+ }
}
module.exports.postcss = true
注意,插件将会再次遍历那些所有变更过或者新增的节点。所以你应该主动去检查插件执行转换的这个流程是否已经被执行过,以及判断该种情况是否需要忽略这些节点。记住只有 Once
以及 OnceExit
监听器(listener)才只会被真正调用一次。
const plugin = () => {
return {
Declaration(decl) {
console.log(decl.toString());
decl.value = "red";
},
};
};
plugin.postcss = true;
await postcss([plugin]).process("a { color: black }", { from });
// => color: black
// => color: red
如果你的插件大到难以被重写,继续在 Root
监听器(listener)里面使用 walk
方法也不失为一种方法。
新版的 PostCSS 包含两种不同类型的监听器(listener):“enter” 以及 “exit”。Once
、Root
、AtRule
、或者 Rule
方法会在该节点下的所有子元素被处理之前调用。OnceExit
、RootExit
、AtRuleExit
以及 RuleExit
会在该节点下的所有子元素被处理之后调用。
如果你需要在两个监听器之间共享数据,你可以使用 prepare()
:
module.exports = (opts = {}) => {
return {
postcssPlugin: "PLUGIN NAME",
prepare(result) {
const variables = {};
return {
Declaration(node) {
if (node.variable) {
variables[node.prop] = node.value;
}
},
OnceExit() {
console.log(variables);
},
};
},
};
};
postcss
代码在 PostCSS 插件新 API 的加持下,你也就没有必要引入 postcss
。因为你可以从 Root
函数的第二个参数里面拿到所有样式以及方法:
- const { list, Declaration } = require('postcss')
module.exports = {
postcssPlugin: 'postcss-example',
- Once (root) {
+ Once (root, { list, Declaration }) {
…
}
}
module.exports.postcss = true
如果你不想马上做,你也可以暂时保持原样,什么都不改。
这一步不做强制规定,不过我们想给 clean-publish 工具打个广告,该工具能够在你发布 npm 包之前,清理 package.json
里面有关于开发配置的配置项。如果 PostCSS 生态开始准备用它,我们可以把 node_modules
甚至弄的更小。
把下面这行代码加到你的项目里面:
npm install --save-dev clean-publish
现在可以用 npx clean-publish
来替代 npm publish
。
你可以使用官方提供的插件脚手架以及插件,来作为自己学习使用新 API 的范例:
我们推荐使用 Sharec 来管理自己的开发配置,并且它可以实现多个项目共享一个开发配置。去这里,你可以发现 PostCSS 的共享配置。
为了解决大家的问题,我们这边开通 Gitter chat 账号!不要犹豫,快来跟我们分享你们迁移的心路历程或者你插件的语法和架构。我们非常乐于帮助大家排忧解难。
扫码关注w3ctech微信公众号
共收到0条回复