postcss7和postcss8的差异


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) ,大部分的处理时间都会花在插件上,一遍又一遍地遍历树。

扫描二维码关注公众号,回复: 14561012 查看本文章
// 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 点我加入

猜你喜欢

转载自blog.csdn.net/weixin_43974265/article/details/119676374