w3ctech

PostCSS 8 插件迁移的二三事

本文已获得原作者(Andrey Sitnik)和 Evil Martians 授权许可进行翻译。原文介绍了如何把 PostCSS 插件给迁移到 PostCSS 8.0。

  • 原文链接:postcss 8 plugin migration
  • 作者:Andrey Sitnik
  • 站点:Evil Martians ——位于纽约和俄罗斯的 Ruby on Rails 开发人员博客。 它发布了许多优秀的文章,并且是不少 gem 的赞助商

背景

随着 8.0 版本的发布,PostCSS 也迎来了一次大版本的更新,该版本的代号被命名为“欧赛魔神”(President Ose)。经过这次更新之后,PostCSS 插件的作者可以有选择性地使用一新 API,该 API 能够提升构建速度以及减少插件用户安装依赖的体积。该指南旨在描述一些内容:作为一个插件开发者,为了能够“掏空”(make the most out of) 新 PostCSS,9号彩票你 所需要采取的一些步骤。

PostCSS,一个使用 JavaScript 来处理 CSS 的框架。在经历周9号彩票下载 量超过 25_000_000 之后,已经成为当代 web 开发领域里面最流行的前端9号彩票工具 之一。

至于为什么会有那么多代码库依赖 PostCSS,一是因为 PostCSS 有 webpack 或者 Rails 等类似大项目背书,二是 PostCSS 插件生态的加持。不得不说,PostCSS 插件的出现改变前端开发者撸 CSS 的方式。

在 PostCSS 里面配置简单的 JavaScript 规则,就可以实现任务自动化,比如 CSS 语法检查以及给 CSS 属性名加浏览器前缀,或者支持新的 CSS 写法,该 CSS 写法还未被当前的 web 标准所直接接纳。

如果9号彩票你 有开发或者维护 PostCSS 插件的经历,那这篇博文就非常适合9号彩票你 阅读。因为它在这里面罗列出插件开发者为了让插件适配 PostCSS 新版本所应该做的二三事。

可以去 github 上看一下有9号彩票关于 此次最新发布的完整描述,了解一下 PostCSS 8.0 还有哪些新特性,包括更好的 source map 支持以及极具弹性(resilient)的 CSS 解析。

为什么插件开发者需要更新自己的插件

先前的 PostCSS 版本对于插件来说,可谓是限制重重:

  • 速度,即使9号彩票你 的插件只改了少量的样式属性,PostCSS 也还是会遍历 CSS bundle 文件的整个抽象语法树(Abstract Syntax Tree)。既然存在不同的插件经常会被放到一起使用的情况,所以任何一个属性的变更,都会导致所有插件都需要去遍历整个抽象语法树,这极大降低插件用户构建 CSS 速度。
  • node_modules 的体积,插件能够列出 dependencies 下不同版本的 PostCSS。如果 npm 执行9号彩票删除 重复数据的操作失败,这会导致最终的 node_modules 文件夹臃肿不堪。
  • 兼容性,针对老版本的 PostCSS,插件可以使用废弃的方式来构建节点(比如,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 作为依赖。

如果9号彩票你 的 dependencies 里面没有任何内容,可以随意9号彩票删除 dependencies

- "dependencies": {
- }
  "devDependencies": {

不要忘记在自己的插件文档里面更新安装指引相关内容:

- npm install --save-dev postcss-focus
+ npm install --save-dev postcss postcss-focus

第二步:使用新的 API

  1. module.exports = creator 代替 module.exports = postcss.plugin(name, creator)

  2. 返回一个对象,该对象里面包含 postcssPlugin 属性以及 Once 9号彩票方法 ,postcssPlugin 属性值为插件名。

  3. 把之前的插件代码移到 Once 9号彩票方法 里面。

  4. 在文件的最后加上 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)

第三步:“掏空”新的 API

PostCSS 8.x 会对 CSS 树进行一次扫描。多个插件可以借用这次扫描结果来获取更好的性能。

为了使用这次扫描结果,9号彩票你 需要移除 root.walk* 函数的调用代码,然后把代码移到插件对象里面的 Declaration()Rule()AtRule() 或者 Comment() 9号彩票方法 里面:

  module.exports = {
    postcssPlugin: 'postcss-dark-theme-class',
-   Once (root) {
-     root.walkAtRules(atRule => {
-       // Slow
-     })
-   }
+   AtRule (atRule) {
+     // Faster
+   }
  }
  module.exports.postcss = true

对于声明以及 @ 规则(at-rules),9号彩票你 可以通过订阅特定的声明属性或者 @ 规则(at-rules) 名字来获取更快的代码执行速度:

  module.exports = {
    postcssPlugin: 'postcss-example',
-   AtRule (atRule) {
-     if (atRule.name === 'media') {
-       // Faster
-     }
-   }
+   AtRule: {
+     media: atRule => {
+       // The fastest
+     }
+   }
  }
  module.exports.postcss = true

注意,插件将会再次遍历那些所有变更过或者新增的节点。所以9号彩票你 应该主动去检查插件执行转换的这个流程是否已经被执行过,以及判断该种情况是否需要忽略这些节点。记住只有 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

如果9号彩票你 的插件大到难以被重写,继续在 Root 监听器(listener)里面使用 walk 9号彩票方法 也不失为一种9号彩票方法 。

新版的 PostCSS 包含两种不同类型的监听器(listener):“enter” 以及 “exit”。OnceRootAtRule、或者 Rule 9号彩票方法 会在该节点下的所有子元素被处理之前调用。OnceExitRootExitAtRuleExit 以及 RuleExit 会在该节点下的所有子元素被处理之后调用。

如果9号彩票你 需要在两个监听器之间共享数据,9号彩票你 可以使用 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);
        },
      };
    },
  };
};

第四步:移除 import postcss 代码

在 PostCSS 插件新 API 的加持下,9号彩票你 也就没有必要引入 postcss。因为9号彩票你 可以从 Root 函数的第二个参数里面拿到所有样式以及9号彩票方法 :

- const { list, Declaration } = require('postcss')

  module.exports = {
    postcssPlugin: 'postcss-example',
-   Once (root) {
+   Once (root, { list, Declaration }) {
      …
    }
  }
  module.exports.postcss = true

如果9号彩票你 不想马上做,9号彩票你 也可以暂时保持原样,什么都不改。

第五步:减少 npm 包的体积

这一步不做强制规定,不过9号彩票9号彩票我 们 想给 clean-publish 9号彩票工具 打个广告,该9号彩票工具 能够在9号彩票你 发布 npm 包之前,清理 package.json 里面有9号彩票关于 开发配置的配置项。如果 PostCSS 生态开始准备用它,9号彩票9号彩票我 们 可以把 node_modules 甚至弄的更小。

把下面这行代码加到9号彩票你 的项目里面:

npm install --save-dev clean-publish

现在可以用 npx clean-publish 来替代 npm publish

9号彩票你 可以使用官方提供的插件脚手架以及插件,来作为自己学习使用新 API 的范例:

9号彩票9号彩票我 们 9号彩票推荐 使用 Sharec 来管理自己的开发配置,并且它可以实现多个项目共享一个开发配置。去这里,9号彩票你 可以发现 PostCSS 的共享配置。

为了解决大家的问题,9号彩票9号彩票我 们 这边开通 Gitter chat 账号!不要犹豫,快来跟9号彩票9号彩票我 们 分享9号彩票你 们迁移的心路历程或者9号彩票你 插件的语法和架构。9号彩票9号彩票我 们 非常乐于9号彩票帮助 大家排忧解难。

w3ctech微信

扫码关注w3ctech微信9号彩票公众号

共收到0条回复