首页 > 解决方案 > Postcss 8 插件:如何避免循环进入声明函数?

问题描述

您好 postcss 专家!

我正在将旧插件更新为 postCSS 8 API,但遇到了一些问题。

这个简单的 postCSS 插件陷入了一个无限循环:

module.exports = (options = {}) => {
  return {
    postcssPlugin: 'postcss-failing-plugin',
    Declaration(decl) {
      if (decl.prop.startsWith('--')) {
        decl.prop = decl.prop.replace(/^--/, `--prefix-`);
      }
    },
  };
};

module.exports.postcss = true;

文档提到了这种行为:

插件将重新访问您更改或添加的所有节点。如果您要更改任何子级,插件也会重新访问父级。只有Once并且OnceExit不会再次调用。 写一个插件

但没有什么可以避免的。

如何在Declaration不进行无限循环的情况下编辑值?

标签: postcss

解决方案


您可能会反复向已添加前缀的自定义属性声明添加前缀,从而导致声明访问者无限运行。

您可以使用否定前瞻断言 (?!)来匹配以特定自定义属性前缀开头的自定义属性,即^--(?!prefix-).

const matcher = /^--(?!prefix-)/
const replacement = '--prefix-'

const ensure = value => value.replace(matcher, replacement)

// these _should not_ receive a new prefix
ensure('foo')          // "foo"
ensure('prefix-foo')   // "prefix-foo"
ensure('--prefix-foo') // "--prefix-foo"

// these _should_ receive a new prefixed
ensure('--foo')            // "--prefix-foo"
ensure('--prefixable-foo') // "--prefix-prefixable-foo"

如适用于您的示例

module.exports = (options = {}) => {
  return {
    postcssPlugin: 'postcss-failing-plugin',
    Declaration(decl) {
      /** Matches a `--` property not beginning with `--prefix-`. */
      const match = /^--(?!prefix-)/

      if (match.test(decl.prop)) {
        decl.prop = decl.prop.replace(match, `--prefix-`);
      }
    },
  };
};

module.exports.postcss = true;

推荐阅读