stylex-webpack
First introduced by Frank Yan at React Conf 2020, StyleX framework agnostic CSS-in-JS system with near-zero runtime, ahead-of-time compiler, atomic CSS extraction that powers Facebook and Instagram.
Motivation
stylex offers a CSS-in-JS compiler, allowing you to write CSS in your JavaScript/JSX/TSX. However, unlike other CSS-in-JS solutions that gather and process styles within the browser, stylex will read your source code, collect your style and transform your JS/JSX/TSX, stripping runtime calls as much as possible (making the value of className
a static string literal), and output CSS elsewhere.
StyleX does provide a webpack plugin. Under the hood, it will traverse through the source code, collect styles, and emit a new CSS asset during the webpack compilation. However, it does come with some limitations:
- StyleX's official Next.js setup requires a
.babelrc
file, which disables Next.js' built-in SWC compiler. - StyleX's official Next.js plugin requires a CSS asset to pre-exist so that it can append the extracted CSS to it.
I start this project as a Proof of Concept, to see if it is possible to make a webpack plugin for ststylex that doesn't disable Next.js' SWC compiler. I have already made a similar webpack plugin for style9, which is also an AoT atomic CSS-in-JS system that is inspired by StyleX.
Unlike stylex's official webpack plugin, stylex-webpack
requires you have setup css-loader
and MiniCssExtractPlugin
in your webpack configuration, just like your normal CSS based webpack project. stylex-webpack
's built-in loader will generate a virtual CSS import containing a dummy CSS rule. This allows the MiniCssExtractPlugin
to collect those virtual CSS imports and emit a CSS asset, which stylex-webpack
will later inject the actual extracted CSS into at the processAssets
stage.
Installation
npm i stylex-webpack
yarn add stylex-webpack
pnpm add stylex-webpack
Usage
Webpack
const { StyleXPlugin } = require('stylex-webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader']
}
]
},
plugins: [
new StyleXPlugin({
}),
new MiniCssExtractPlugin(),
new CssMinimizerPlugin()
]
};
Next.js
const { withStyleX } = require('stylex-webpack/next');
module.exports = withStyleX({
})({
reactStrictMode: true
});
Options
webpack
new StyleXPlugin({
stylexOption: {
dev: process.env.NODE_ENV === 'development',
test: process.env.NODE_ENV === 'test'
},
stylexImports: ['stylex', '@stylexjs/stylex'],
useCSSLayers?: boolean,
transformCss(css) {
const postcss = require('postcss');
const autoprefixer = require('autoprefixer');
const sortMediaQueries = require('postcss-sort-media-queries');
return postcss([
autoprefixer({
}),
sortMediaQueries({
sort: 'mobile-first'
})
]).process(css, { from: undefined }).css;
const browserslist = require('browserslist');
const { transform, browserslistToTargets } = require('lightningcss');
return transform({
code: Buffer.from(css),
targets: browserslistToTargets(browserslist('>= 0.25%'))
}).code;
return css;
}
});
Next.js
withStyleX({
stylexOption: {
},
})
It is recommended to use postcss-sort-media-queries
as a workaround for stylex's known issue with sorting at-rules and media queries. You can configure it in your PostCSS configuration file, and stylex-webpack
will automatically apply your PostCSS configuration to the extracted CSS just like Next.js' built-in PostCSS support.
module.exports = {
plugins: [
[
require.resolve('postcss-sort-media-queries'),
{
sort: 'mobile-first'
}
],
require.resolve('next/dist/compiled/postcss-flexbugs-fixes'),
[
require.resolve('next/dist/compiled/postcss-preset-env'),
{
browsers: ['defaults'],
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3,
features: {
'custom-properties': false
}
}
]
]
};
Author
stylex-webpack © Sukka, Released under the MIT License.
Authored and maintained by Sukka with help from contributors (list).
Personal Website · Blog · GitHub @SukkaW · Telegram Channel @SukkaChannel · Twitter @isukkaw · Mastodon @sukka@acg.mn · Keybase @sukka