我正在开发一个postCSS插件,您可以在其中将自定义atRules用于bem类。这是演示: https://astexplorer.net/#/gist/147ddf920699ac24b690a05f8f8da8f1/15aeb3c85224f3d20de47a1774c25f330ed9d16e
它自己可以很好地工作,但是当在项目中与自动前缀一起使用时,自动前缀会产生错误:TypeError: Cannot read property '_autoprefixerPrefix' of undefined
。
您可能想到的任何原因或任何调试方法?
您还可以将以下所有代码复制粘贴到npm runkit中以获取确切的错误。
const autoprefixer = require("autoprefixer");
const postcss = require('postcss');
const css = `
@b BaseButton {
@apply shadow-neon-default;
@apply rounded-full;
box: horizontal;
position: relative;
overflow: hidden;
user-select: none;
&:hover {
@apply shadow-neon-less;
}
&:active {
@apply shadow-neon-inset;
}
@is faded {
opacity: 0.8;
}
}
`;
const toTitleCase = (str) => {
return str.replace(/\w\S*/g, function(txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
});
};
const createRule = (selector, { source, nodes, raws }) => {
return postcss.rule({
selector,
source,
nodes,
raws
});
};
const recycleBin = {
element: [],
modifier: [],
is: [],
when: [],
whenIs: []
};
const emptyRecycleBin = (type) => {
recycleBin[type].forEach((rule) => {
rule.remove();
});
};
const willInsert = [];
const insertEverything = (root) => {
Object.values(willInsert).forEach((insertInstruction) => {
insertInstruction.rules.reverse().forEach((rule) => {
root.insertAfter(insertInstruction.baseRule, rule);
});
insertInstruction.baseRule.remove();
});
};
let newBlock = null;
const processBlocks = (container, next) => {
container.walkAtRules(/^block$|^b$/gi, (blockAtRule) => {
willInsert[`.${blockAtRule.params}`] = {
baseRule: blockAtRule,
rules: []
};
newBlock = createRule(`.${blockAtRule.params}`, blockAtRule);
willInsert[`.${blockAtRule.params}`].rules.push(newBlock);
next(newBlock);
});
};
const processElements = (container, blockName, next) => {
container.walkAtRules(/^element$|^e$/gi, (elementAtRule) => {
const newElement = createRule(`${container.selector}__${elementAtRule.params}`, elementAtRule);
willInsert[blockName].rules.push(newElement);
recycleBin.element.push(elementAtRule);
next(newElement);
});
emptyRecycleBin('element');
};
const processModifier = (container, blockName) => {
container.walkAtRules(/^modifier$|^m$/gi, (modifierAtRule) => {
const newModifier = createRule(`${container.selector}--${modifierAtRule.params}`, modifierAtRule);
willInsert[blockName].rules.push(newModifier);
recycleBin.modifier.push(modifierAtRule);
});
emptyRecycleBin('modifier');
};
const processIs = (container, blockName) => {
container.walkAtRules('is', (isAtRule) => {
if (isAtRule.parent.name !== 'when') {
const newModifier = createRule(`${container.selector}--is${toTitleCase(isAtRule.params)}`, isAtRule);
willInsert[blockName].rules.push(newModifier);
recycleBin.is.push(isAtRule);
}
});
emptyRecycleBin('is');
};
const processWhen = (container, blockName, cb) => {
container.walkAtRules('when', (whenAtRule) => {
const newWhen = createRule(`[class*='${container.selector.substring(1)}--${whenAtRule.params}']`, whenAtRule);
willInsert[blockName].rules.push(newWhen);
newWhen.walkAtRules('is', (isAtRule) => {
const newIs = createRule(`${newWhen.selector.slice(0, -2)}:${isAtRule.params}']`, isAtRule);
willInsert[blockName].rules.push(newIs);
recycleBin.whenIs.push(isAtRule);
});
emptyRecycleBin('whenIs');
recycleBin.when.push(whenAtRule);
});
emptyRecycleBin('when');
};
const process = (root) => {
processBlocks(root, (processedBlock) => {
processElements(processedBlock, processedBlock.selector, (processedElement) => {
processModifier(processedElement, processedBlock.selector);
processIs(processedElement, processedBlock.selector);
processWhen(processedElement, processedBlock.selector);
});
processModifier(processedBlock, processedBlock.selector);
processIs(processedBlock, processedBlock.selector);
processWhen(processedBlock, processedBlock.selector);
insertEverything(root);
});
};
const bemmify = postcss.plugin('postcss-bem', (options = {}) => {
return (root) => {
process(root);
};
});
postcss([ bemmify, autoprefixer ]).process(css).then(result => {
result.warnings().forEach(warn => {
console.warn(warn.toString())
})
console.log(result.css)
});