Skip to content

Instantly share code, notes, and snippets.

@newbornfrontender
Created January 5, 2019 17:03
Show Gist options
  • Select an option

  • Save newbornfrontender/cb77fe9b391418fb6a0fbe5e84fc5886 to your computer and use it in GitHub Desktop.

Select an option

Save newbornfrontender/cb77fe9b391418fb6a0fbe5e84fc5886 to your computer and use it in GitHub Desktop.
Babel (plugin) - PostCSS - Tagged templates
const postcss = require('postcss');
const postcssrc = require('postcss-load-config');
const deasyncPromise = require('deasync-promise');
const expressionsRegex = /__QUASI_EXPR_(\d+)__/g;
const splitExpressions = (css) => {
let found;
const matches = [];
while ((found = expressionsRegex.exec(css)) !== null) {
matches.push(found);
}
const { prevEnd, quasiTerms, expressionTerms } = matches.reduce(
(acc, match) => {
acc.quasiTerms.push(css.substring(acc.prevEnd, match.index));
const [placeholder, expressionIndex] = match;
acc.expressionTerms.push(expressionIndex);
acc.prevEnd = match.index + placeholder.length;
return acc;
},
{ prevEnd: 0, quasiTerms: [], expressionTerms: [] },
);
quasiTerms.push(css.substring(prevEnd, css.length));
return { quasiTerms, expressionTerms };
};
const buildQuasisAst = (t, terms) =>
terms.map((term, i) =>
t.templateElement(
{
raw: term,
cooked: term,
},
i === terms.length - 1,
),
);
const generateExpressionPlaceholder = (i) => `__QUASI_EXPR_${i}__`;
module.exports = ({ types: t }) => ({
visitor: {
TaggedTemplateExpression({ node }, { file }) {
const {
tag,
quasi: { quasis, expressions },
} = node;
const {
opts: { filename },
} = file;
if (!tag.name && !tag.name === 'css') return;
let css = quasis.reduce((acc, { value: { raw } }, i) => {
const expr = expressions[i] ? generateExpressionPlaceholder(i) : '';
return `${acc}${raw}${expr}`;
}, '');
const { plugins, options } = deasyncPromise(postcssrc());
const { css: processed } = deasyncPromise(
postcss(plugins).process(css, { from: filename, ...options }),
);
const { quasiTerms, expressionTerms } = splitExpressions(processed);
const quasisAst = buildQuasisAst(t, quasiTerms);
const expressionsAst = expressionTerms.map(
(exprIndex) => expressions[exprIndex],
);
quasis.splice(0, quasis.length, ...quasisAst);
expressions.splice(0, expressions.length, ...expressionsAst);
},
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment