Stylesheet Extraction
Stylesheet extraction is highly recommended for all component libraries and applications, so that generated class names can be combined and de-duplicated into one external stylesheet. This allows you to enjoy the decreased stylesheet size that comes with atomic styling.
There are two types of stylesheet extraction:
- Platform stylesheet extraction
- Parcel / Webpack stylesheet extraction
Which type should I use?
If your package is a component library, use our platform stylesheet extraction. This includes Atlassian Design System packages like @atlaskit/button
or any other package that is treated as a platform offering or used across products or repositories.
If your package exists in the same codebase as, and is directly consumed by, a Webpack or Parcel app, use Parcel stylesheet extraction or Webpack stylesheet extraction depending on what bundler your app uses.
Note that Parcel and Webpack are the only bundlers we support.
Platform stylesheet extraction
Platform stylesheet extraction only works if you use Babel to build your component library. Note that we do not recommend nor support using bundlers (e.g. Webpack or Parcel) to build your component library, because bundlers are appropriate for web apps (e.g. Jira) and not for component libraries.
Warning
Ensure that any apps that import your component library also have the Compiled Webpack or Parcel plugins installed (@compiled/webpack-loader
or@compiled/parcel-config
), otherwise the order in which the styles are applied will become unpredictable. This can be an issue if you have styles that overlap, e.g. if you mixpadding
andpaddingTop
in the same component, or have@media
queries that potentially overlap.
If the apps that import your component library use other bundlers like Vite or Next.js, or if your apps cannot install the Compiled Webpack or Parcel plugins, stylesheet extraction will still work! However, you must make sure that within each component, you should never mix any CSS properties or styles that overlap.
Add @compiled/babel-plugin-strip-runtime
to your Babel configuration, with extractStylesToDirectory
set as an option. Set source
to the folder your component library's source code is defined in, and dest
to the folder your component library's build output is generated to.
For example:
// babel.config.js
module.exports = {
plugins: [
// This will handle all `token()` calls outside of
// Compiled usages
'@atlaskit/tokens/babel-plugin',
// ↓↓ Compiled should run last ↓↓
[
'@compiled/babel-plugin',
{
transformerBabelPlugins: ['@atlaskit/tokens/babel-plugin'],
},
],
[
'@compiled/babel-plugin-strip-runtime',
{
extractStylesToDirectory: {
source: 'src',
dest: 'dist',
},
},
],
],
};
Your dest
may vary depending on how you generate your dist/
folder in your component library. For example, if you have mutliple cjs
and esm
distributions, those will each need a separate dest
through Babel's environment-specific configuration.
In each component library's package.json
file, you will also need to add "sideEffects": ["**/*.compiled.css"]
, to ensure that the Compiled stylesheets that are generated are exempt from Webpack's and Parcel's tree-shaking (which would delete the stylesheets!):
{
"name": "@example/my-component-library",
// …
"dependencies": {
// Replace "version" with the latest version
"@compiled/react": "^version"
},
// …
"sideEffects": ["**/*.compiled.css"]
// …
}
To test whether you've set up stylesheet extraction correctly, use your component library's usual build command (e.g. yarn build
). Inside the dist
folder, you should see some .compiled.css
stylesheets generated, one for each .tsx
file that uses @compiled/react
.
For example, if you have a file with the path packages/design-system/button/dist/cjs/button.js
that uses Compiled, you can expect there to be a corresponding packages/design-system/button/dist/cjs/button.compiled.css
.
Parcel stylesheet extraction
If you are using a web app that uses Parcel, first install the Parcel loader.
Then configure the extract
plugin to true
in your Compiled configuration. For example:
// .compiledcssrc
{
"extract": true, // <-- add this
"transformerBabelPlugins": [["@atlaskit/tokens/babel-plugin"]]
}
Note that stylesheet extraction feature is disabled on local development due to a known issue.
See the @compiled/parcel-config
documentation for information about other configuration options.
Webpack stylesheet extraction
If your web app uses Webpack, first install the webpack loader.
Then configure the extract
option to true
in the webpack loader and turn on the extract plugin.
// webpack.config.js
+const { CompiledExtractPlugin } = require('@compiled/webpack-loader');
module.exports = {
module: {
rules: [
{
test: /\.(js|ts|tsx)$/,
exclude: /node_modules/,
use: [
{ loader: 'babel-loader' },
{
loader: '@compiled/webpack-loader',
+ options: {
+ extract: true,
+ },
},
],
},
],
},
+ plugins: [
+ new CompiledExtractPlugin(),
+ ],
};
For more configuration options see the loader package docs.
CSS configuration
Add loaders to handle and extract found styles. We support and recommend mini-css-extract-plugin
; we don't currently support other CSS loaders. Note: mini-css-extract-plugin
dropped support for Webpack v4 in 2.0.0, Webpack v4 users will need to use mini-css-extract-plugin@1.6.2
.
npm i css-loader mini-css-extract-plugin --save-dev
If you don't already handle .css
files in your webpack.config.js
, you can update it like this:
// webpack.config.js
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.(js|ts|tsx)$/,
exclude: /node_modules/,
use: [
{ loader: 'babel-loader' },
{
loader: '@compiled/webpack-loader',
options: {
extract: true,
},
},
],
},
+ {
+ test: /\.css$/i,
+ use: [MiniCssExtractPlugin.loader, 'css-loader'],
+ },
],
},
plugins: [
+ new MiniCssExtractPlugin({ filename: '[name].[contenthash].css' }),
new CompiledExtractPlugin(),
],
};
Note that we don't currently support style-loader
for loading css
files from Compiled. If you are using style-loader
, or you're using a different loader for your css
files already, you can use regular expressions to ensure that both Compiled's css
files and your other css
files are loaded correctly:
// webpack.config.js
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.(js|ts|tsx)$/,
exclude: /node_modules/,
use: [
{ loader: 'babel-loader' },
{
loader: '@compiled/webpack-loader',
options: {
extract: true,
},
},
],
},
+ {
+ test: /compiled-css\.css$/i,
+ use: [MiniCssExtractPlugin.loader, 'css-loader'],
+ },
// The following loader will be used for css files that are not from Compiled.
{
- test: /\.css$/i,
+ test: /(?<!compiled-css)(?<!\.compiled)\.css$/,
// Put your existing css loader configuration here
use: ['style-loader', 'css-loader'],
},
],
},
plugins: [
+ new MiniCssExtractPlugin(),
new CompiledExtractPlugin(),
],
};
All extracted styles will be placed in a file called compiled-css.css
.
Production optimization
Filename
Some production environments may require you to include a hash in the filename to allow the stylesheet to be cached correctly.
To do this, pass the filename
option to the extract plugin, including [contenthash]
in the name.
// webpack.config.js
-new MiniCssExtractPlugin()
+new MiniCssExtractPlugin({ filename: '[name].[contenthash].css' })
See the mini-css-extract-plugin
docs for more information on the available options.
CSS minification
Turn on the minimizer plugin.
npm i css-minimizer-webpack-plugin --save-dev
// webpack.config.js
+const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
+ mode: 'production',
module: {
rules: [
{
test: /\.(js|ts|tsx)$/,
exclude: /node_modules/,
use: [
{ loader: 'babel-loader' },
{
loader: '@compiled/webpack-loader',
options: {
extract: true,
},
},
],
},
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
plugins: [
new MiniCssExtractPlugin({ filename: '[contenthash].[name].css' })
new CompiledExtractPlugin(),
],
+ optimization: {
+ minimizer: [
+ '...',
+ new CssMinimizerPlugin(),
+ ],
+ },
};
Suggest changes to this page ➚