DEV Community

Cover image for Using vanilla-extract in an nx workspace (webpack)
Layton Whiteley
Layton Whiteley

Posted on • Edited on

Using vanilla-extract in an nx workspace (webpack)

Overview

Recently, I have been curious about zero-runtime css-in-js libraries and the performance benefits they bring. One such library, relatively new, is vanilla-extract. Because I like to build projects with nx, I was curious if there is already support for it but currently there isn't as yet.

This aims to show a quick and easy way to add support for vanilla-extract in a react/webpack app in an nx workspace.

What is vanilla-extract?

vanilla-extract is all about zero-runtime style sheets in TypeScript (or JavaScript). If you’ve used Sass or Less in the past, you already know how powerful they can be for things like theming, organization, and preprocessing of your app’s styles.

Setup

Let's create a workspace

Please see below the command to create the nx workspace and the options taken to follow along.

Note: the current version of nx at this time is 15.0.1

npx create-nx-workspace@latest

# Choose your style: Integrated
# What to create in the new workspace: react
# Repository name: vanilla
# Application name: example-web
# Default stylesheet format: CSS
# Enable distributed caching to make your CI faster: No
Enter fullscreen mode Exit fullscreen mode

Install dependencies

npm i @vanilla-extract/css
npm i --save-dev @vanilla-extract/webpack-plugin
Enter fullscreen mode Exit fullscreen mode

Create custom webpack config

In order to add support, we need to do a few things:

  • Create a file: apps/example-web/webpack.config.js
  • Add rules for the css generated by vanilla-extract
  • Prepend these rules in the rules array already provided by nx
  • Replace the rules array
// file: apps/example-web/webpack.config.js
const { VanillaExtractPlugin } = require('@vanilla-extract/webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = (config) => {
  const cssRule = config.module.rules.find((rule) =>
    rule.test.toString().includes('css')
  );

  const rulesWithoutCss = config.module.rules.filter(
    (rule) => !rule.test.toString().includes('css')
  );

  const rules = [
    ...rulesWithoutCss,
    {
      ...cssRule,
      oneOf: [
        {
          test: /\.vanilla\.css$/i, // Targets only CSS files generated by vanilla-extract
          use: [
            MiniCssExtractPlugin.loader,
            {
              loader: require.resolve('css-loader'),
              options: {
                url: false, // Required as image imports should be handled via JS/TS import statements
              },
            },
          ],
        },
        ...cssRule.oneOf,
      ],
    },
  ];

  return {
    ...config,
    plugins: [...config.plugins, new VanillaExtractPlugin()],
    module: {
      ...config.module,
      rules,
    },
  };
};
Enter fullscreen mode Exit fullscreen mode

Use the custom webpack config

In the file apps/example-web/project.json,
find the property webpackConfig and replace it with

"webpackConfig": "apps/example-web/webpack.config.js",
Enter fullscreen mode Exit fullscreen mode

Create and use your styles

Create file apps/example-web/src/app/app.css.ts

import { style } from '@vanilla-extract/css';

export const container = style({
  padding: 10,
  background: 'blue',
});
Enter fullscreen mode Exit fullscreen mode

Modify file: apps/example-web/src/app/app.tsx

import { container } from './app.css';
import NxWelcome from './nx-welcome';

export function App() {
  return (
    <div className={container}>
      <NxWelcome title="example-web" />
      <div />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Run the application

npm run start example-web
Enter fullscreen mode Exit fullscreen mode

Thats it!

  • You will now see that the page's background is blue. Not the prettiest thing but just to prove it works.
  • Upon inspecting the network, you can locate the css file vendor.css (at this time and for this example) which has the generated styles

Your next steps

  • Try it out
  • make your own customisations like changing the exported css file name, etc.
  • Leave feedback; I'd love to see how this can be improved.

see sample repository for completed solution

https://github.com/lwhiteley/nx-vanilla-extract-setup

Feature request for nx: https://github.com/nrwl/nx/issues/12771

Top comments (2)

Collapse
 
shaydavidson profile image
Shay Davidson

thanks for this!

there's a slight typo in the webpack config - should be cssRule instead of cssRules.

Collapse
 
lwhiteley profile image
Layton Whiteley

Hey glad you found it helpful.

Thanks for spotting..will adjust