@stylexjs/postcss-plugin
Version:
PostCSS plugin for StyleX
103 lines (86 loc) • 3.08 kB
JavaScript
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const postcss = require('postcss');
const createBuilder = require('./builder');
module.exports = function createPlugin() {
const PLUGIN_NAME = '@stylexjs/postcss-plugin';
const builder = createBuilder();
const isDev = process.env.NODE_ENV === 'development';
const plugin = ({
cwd = process.cwd(),
// By default reuses the Babel configuration from the project root.
// Use `babelrc: false` to disable this behavior.
babelConfig = {},
include,
exclude,
useCSSLayers = false,
importSources = ['@stylexjs/stylex', 'stylex'],
}) => {
exclude = [
// Exclude type declaration files by default because it never contains any CSS rules.
'**/*.d.ts',
'**/*.flow',
...(exclude ?? []),
];
// Whether to skip the error when transforming StyleX rules.
// Useful in watch mode where Fast Refresh can recover from errors.
// Initial transform will still throw errors in watch mode to surface issues early.
let shouldSkipTransformError = false;
return {
postcssPlugin: PLUGIN_NAME,
plugins: [
// Processes the PostCSS root node to find and transform StyleX at-rules.
async function (root, result) {
const fileName = result.opts.from;
// Configure the builder with the provided options
await builder.configure({
include,
exclude,
cwd,
babelConfig,
useCSSLayers,
importSources,
isDev,
});
// Find the "@stylex" at-rule
const styleXAtRule = builder.findStyleXAtRule(root);
if (styleXAtRule == null) {
return;
}
// Get dependencies to be watched for changes
const dependencies = builder.getDependencies();
// Add each dependency to the PostCSS result messages.
// This watches the entire "./src" directory for "./src/**/*.{ts,tsx}"
// to handle new files and deletions reliably in watch mode.
for (const dependency of dependencies) {
result.messages.push({
plugin: PLUGIN_NAME,
parent: fileName,
...dependency,
});
}
// Build and parse the CSS from collected StyleX rules
const css = await builder.build({
shouldSkipTransformError,
});
const parsed = await postcss.parse(css, {
from: fileName,
});
// Replace the "@stylex" rule with the generated CSS
styleXAtRule.replaceWith(parsed);
result.root = root;
if (!shouldSkipTransformError) {
// Build was successful, subsequent builds are for watch mode
shouldSkipTransformError = true;
}
},
],
};
};
plugin.postcss = true;
return plugin;
};