# How to create a Webpack 5 Loader with Preons

### Why a Webpack Loader

[Webpack](https://webpack.js.org/) helps make frontend development more streamlined and recently, I wanted to transform YAML into CSS as part of the build process using the [Preons](https://github.com/preons/preons) library.

By the end of this article:

- you will create a Webpack loader that converts a YAML configuration file into CSS
- you will manually test the loader against a basic HTML page
- you will know how to create your own Webpack loader in future

### Background

Preons (and disclaimer, a project of mine) is a functional CSS utility library. You configure the utility classes in YAML.

Webpack is a popular module bundler, and one helpful thing it does is transform [Sass](https://sass-lang.com/) into CSS with a few useful community loaders.

## Pre-requisites

To follow this tutorial, you need:

- Node 12+. [Install Node's](https://nodejs.org/en/) command-line tool.
- Yarn. [Install Yarn](https://yarnpkg.com/getting-started/install)'s a command-line tool.
- Have a basic knowledge of javascript

## Step 1: Creating a new project

You will create a basic empty project and initialise npm to begin installing local node packages.

Execute the following command to create a new project folder:

```
mkdir custom-webpack-loader && cd custom-webpack-loader
```

Initialise Node's package manager:

```
yarn init
```

You will be asked a series of questions:

```bash
yarn init v1.22.4
question name (custom-webpack-loader): 
question version (1.0.0): 
question description: 
question entry point (index.js): 
question repository url: 
question author: 
question license (MIT): 
question private: 
success Saved package.json
```

By the end, you will have a basic `package.json` without any dependencies. But you'll add them in a few step.

## Step 2 - Configuring Webpack

In this step, you will create a webpack configuration file and tweak it to load a YAML file. It will allow you to test the loader as if you were using it in a project.

Install Webpack and Webpack's CLI to give you access to the Webpack builder:

```bash
yarn add webpack webpack-cli
```

Next, you'll create the `webpack.config.js`:

```bash
touch webpack.config.js
```

In `webpack.config.js`, add:

```js
const path = require("path");

module.exports = {
  //...
  mode: "development",
  entry: path.resolve(__dirname, "fixtures") + "/preons.js",
  module: {
    rules: [
      {
        test: /\.ya?ml$/,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: path.resolve(__dirname, "lib") + "/loader.js"
          },
          "yaml-loader",
        ],
      },
    ],
  },
};

```

- The `mode` property tells Webpack to make optimisations based on environments. In production, however, you would change the `mode` to `production`. However, for this use case, the default will be `development`.
- Notice how the `.module.rules[0].test` catches `.yaml` and `.yml` files based on regex rules.
- The `entry` file points to a  fixtures directory as that directory has files for you to test.
- There are four loaders, 3 of which are existing npm packages. Webpack will apply rules from bottom to top, so first, the `yaml-loader` will take YAML and convert it into JSON. Your loader will transform Javascript into CSS; afterwards, the `css-loader` will apply its transformation and finally, the `style-loader` takes css and puts it into style blocks that are inserted into your page through Webpack's script.

Install other dependency loaders using yarn:

```bash
yarn add style-loader css-loader yaml-loader
```

Now you have a basic Webpack config for testing the loader you're going to build.

## Step 3 - Importing YAML from our input js file

When initially learning about Webpack, one of the strange conventions is not to deal with non-javascript files through the configuration. Instead, you import them as if they are javascript modules themselves. You'll do the same here.

First. Create the `fixtures` directory:

```
mkdir fixtures
```

Next, you need a Preons config file. To save you from learning the syntax and configuring one yourself, install the Preons utility globally.

```bash
npm install preons -g
```

Generate the Preons YAML config:

```bash
preons config > fixtures/preons.yaml
```

You will see a YAML file containing CSS class rules such as `theme-colors`, scales and percentages. The file contents should start like this:

```yaml
preons:
  baseline: 1.6rem
  rules:
    theme-colors:
      black: "#000000"
      white: "#ffffff"
      transparent: transparent
      hotpinkxl: "#f188bc"
```

Create `fixtures/preons.js`. 

```bash
touch fixtures/preons.js
```

Add a require expression to it, so you import the YAML through it.

```js
require("./preons.yaml");
```

Now you have configured the webpack loader to take the `fixtures/preons.js` file and run any YAML imports through the `lib/loader.js`, and it will spit that back out inside a `dist` folder. But before that, you'll need the loader.

## Step 4 - Creating the loader

Now you can build the `loader.js`. The minimum is one exported default function that returns a `module.exports = <>` string.

First, create the `loader.js` file:

```bash
mkdir -p lib && touch lib/loader.js
```

Add the basic method to test the loader is working:

```js
module.exports = function (source) {
  console.log(source)
  return `module.exports = {}`;
};
```

At this point, you can run webpack, and you will see the YAML source load in:

```bash
npx webpack
```

The output will be a lot of JSON, because of the `console.log(source)`. You'll also find a `dist` folder in your project with a `main.js` file.

With the source containing JSON, transforming using the Preons library is only a few more steps. Install Preons locally into the project to access its lib functions to do the transformation of the `preons.yaml` into CSS:

```bash
yarn add preons
```

Change the `lib/loader.js` to parse the YAML JSON into CSS.

```js
const preons = require("preons/src/lib/stylesheet");

module.exports = function (source) {
  let set = JSON.parse(source);
  let css = preons({ set });
  return `module.exports = ${css}`;
};
```

- ` let set = JSON.parse(source)` converts JSON into a javascript object required by the Preons `stylesheet` function.
- `let css = preons({ set });` is a Preons function that transforms the YAML into CSS.
- `return `module.exports = ${css}`;` returns the css as a module to be used by the rest of the Webpack pipeline ruleset.

Now test your webpack pipeline by running:

```bash
npx webpack
```

If you look inside `dist/main.js`, you will find the entirety of Preons CSS generated. To check the generation works, do a grep for the css Property `bg-black`:

```bash
cat dist/main.js | grep "bg-black"
```

## Step 5 - Testing the webpack loader with HTML

Now you are generating CSS from the Preons YAML configuration file. You will want to test you can develop with it.

Create a raw HTML `index.html` file in the root of the project:

```bash
touch index.html
```

Then add a simple starter HTML5 file:

```html
<!DOCTYPE html>
<html class="bg-black">
    <head>
        <link href="https://unpkg.com/browse/preons@0.4.5/dist/reset.css" rel="stylesheet" />
        <script src="dist/main.js" ></script>
    </head>
    <body class="bg-red">
        <h1>Hi</h1>
    </body>
</html>
```

- The `index.html` references Preons reset package as well as your `dist/main.js` file.
- The markup has Preons utility classes such as `bg-black` and `bg-red`. Open the `index.html`, and it will look similar to this:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1609059262499/POAzizHUP.png)

Finally, you want to test that we can make changes to our YAML and it produces CSS instantly.

Start the Webpack dev server to watch for changes using:

```bash
npx webpack --watch
```

Go into the `preons.yaml` and look for the `theme-color -> black`. Change it from `black: "#000000"` to `black: "yellow"`. The file should have this:

```yaml
#....
  rules:
    theme-colors:
      black: "yellow"
```

Refresh the page, and the `bg-black` rule is now `yellow`.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1609059539994/DZXZWOfng.png)

Ok. You will want to keep `bg-black` as it was, but it's just to prove that the generation runs through Webpack. You can now add more colours, change colours or remove them. Of course, you can add any utilities you want using the configuration file. The documentation on how to use the configuration file is still under development, but I'll remember to add it here once it's done.

## Conclusion

You built a Webpack loader to ingest YAML and create CSS to be used as part of a development and production build. You used pre-existing modules (e.g. yaml-loader) to keep your module loader concise.

If you want to continue using Preons, look out for the [Preons webpack loader package](https://www.npmjs.com/package/preons-webpack-loader), so you won't have to maintain it yourself.

Do you have any ideas for your own for a webpack loader?

Also, I hope you enjoyed this article. I'd love feedback on how to improve as a writer and as a developer, so feel free to leave a comment or DM me on Twitter.
