Using vanilla-extract in an nx workspace (webpack)
Tags: vanillaextract, nx, css, typescript
Published: 2022-10-23 16:03:12

## 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`

```bash
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
```

### Install dependencies

```bash
npm i @vanilla-extract/css
npm i --save-dev @vanilla-extract/webpack-plugin
```

### 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


```js
// 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,
    },
  };
};
```

### Use the custom webpack config

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

```json
"webpackConfig": "apps/example-web/webpack.config.js",
```

### Create and use your styles

Create file `apps/example-web/src/app/app.css.ts`
```ts
import { style } from '@vanilla-extract/css';

export const container = style({
  padding: 10,
  background: 'blue',
});
```

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

```ts
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;
```

### Run the application

```bash
npm run start example-web
```

-----

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