postcss7版本和8版本的差异

Posted webchang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了postcss7版本和8版本的差异相关的知识,希望对你有一定的参考价值。


1. postcss是什么

PostCSS 是解析器,它将 CSS 解析为对象树(AST)。然后插件改变了这棵树,最后PostCSS 从一个修改过的对象树生成一个新的 CSS 字符串。

PostCSS 不是一个预处理器,也不是一种添加语法糖的方式,它是一个用于创建 CSS 工具的框架,是一个用 javascript 插件来转换样式的工具。一个 PostCSS 插件是一个接收并且通常从 PostCSS 解析器转换 CSS AST 的函数。PostCSS 让任何有 JavaScript 经验的人都可以创建自己的插件。

2. postcss7

2.1 编写插件

编写适用于postcss7.x版本的插件语法:

// 需要导入postcss
const postcss = require('postcss');

module.exports = postcss.plugin('postcss-merge2', (opts = {}) => {
    return (root, result) => {
        root.walkRules(rule => {
            ...
        })
    }
})

3. postcss8带来的新特性

插件开发者现在可以在postcss8.0中选择使用一个新的 API,这个 API 可以提高构建速度,并减少其工具的最终用户的依赖大小。

3.1 编写插件

编写适用于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

3.2 更小的节点模块

之前,每个插件的依赖关系中都有 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"
  + }
}

3.3 更快的 CSS 构建

之前每一个 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

4. 注意版本差异带来的问题

4.1 问题描述

现在要编写一个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,然后插件就可以正常运行了。

4.2 原因

前边有介绍到编写postcss7.x的插件语法和postcss8.x的插件语法是不一样的。

如果是新手,要编写postcss插件,那么直接去 postcss官网或者postcss的GitHub仓库查资料,它默认会引导我们使用新的插件语法编写适用于postcss8.x的插件。但是,如果项目中的postcss版本是7.x,使用新语法编写的插件就可能有问题,出现下方错误,提示需要使用postcss的8版本

此时有两种解决方法

  1. 仍然使用新插件语法编写插件,同时将项目中postcss的版本升为8,参考postcss8.0插件迁移指南
  2. 项目中postcss版本不变,仍然是7.x,此时要使用老的插件语法编写插件,参考postcss7.x版本的插件

总结:为 postcss7.x创建的插件适用于 postcss8.x,但是为postcss8.x创建的插件不一定适用于postcss7.x。

5. 资料

前端学习交流QQ群:862748629 点我加入

以上是关于postcss7版本和8版本的差异的主要内容,如果未能解决你的问题,请参考以下文章

Java的jdk1.6与jre1.8中存在的差异

C程序存储结构

jQuery版本差异简要分析

vscode代码片段建议bug

Java查看不同版本之间的差异和代码的改动 | 黑马程序员

Haskell:两个版本代码之间的速度差异