DEV Community

Irog Teplostanski
Irog Teplostanski

Posted on

How to Create a Vite Plugin: A Step-by-Step Guide

Before you start creating your own Vite plugin, I strongly recommend reviewing the official documentation on plugin development. This will give you a better understanding of Vite’s architecture and the capabilities of its plugin system. Additionally, it's important to remember that, according to best practices, your plugin's name should start with the vite-plugin prefix. This makes it easier to identify and integrate with other tools and the broader Vite ecosystem.

Creating plugins for Vite is an excellent way to tailor your project’s build process to specific needs. In this article, I'll walk you through how to create a plugin using my own vite-plugin-pretty-module-classnames as an example. This plugin enhances the way CSS modules are handled by adding the filename (minus the -module suffix) to the generated class names, making them more readable and easier to debug.

Step 1: Understanding the Goal

When working with CSS modules in Vite, unique class names are automatically generated to avoid conflicts. However, these names can be somewhat cryptic, especially in large projects. My plugin addresses this issue by adding the filename to the class names (without the -module suffix), making them more meaningful and easier to work with.

Step 2: Creating a Hash

At the core of the plugin is the getHash function, which generates a hash based on the class name. We use the crypto module to create a SHA-256 hash and truncate it to five characters:

import { createHash } from "crypto";

function getHash(input: string): string {
  return createHash("sha256").update(input).digest("hex").slice(0, 5);
}
Enter fullscreen mode Exit fullscreen mode

This function ensures that each class gets a unique identifier appended to its name, preventing any potential conflicts.

Step 3: Generating Unique Class Names

Next, we have the sanitizeModuleClassname function, which creates a new class name by combining the filename, the original class name, and the hash:

function sanitizeModuleClassname(
  name: string,
  filename: string | undefined
): string {
  if (typeof filename !== "string") {
    throw new Error("The filename must be string and cannot be undefined.");
  }

  const parts = filename.split("?")[0].split("/");
  const lastSegment = parts.pop();

  if (!lastSegment) {
    throw new Error("Filename must include a valid file name.");
  }

  const baseFilename = lastSegment.replace(/(\.vue|\.module)?(\.\w+)$/, "");

  const classname = `${baseFilename}__${name}`;
  const hash = getHash(`${classname}`);

  return `${classname}_${hash}`;
}
Enter fullscreen mode Exit fullscreen mode

This function processes the filename, removing the -module suffix and other unnecessary parts like extensions. It then forms a new class name by adding the generated hash.

Step 4: Integrating with Vite

Now, it's time to create the plugin itself. We define it as the PrettyModuleClassnames function, which returns a plugin object:

import type { Plugin, UserConfig } from "vite";

export default function PrettyModuleClassnames(): Plugin {
  return {
    name: "vite-plugin-pretty-module-classnames",
    config(config: UserConfig, {}) {
      if (
        typeof config.css?.modules === "object" &&
        config.css.modules.generateScopedName
      ) {
        throw new Error(
          "Custom settings for generateScopedName are already set. The vite-plugin-pretty-module-classnames plugin cannot be used with other generateScopedName settings."
        );
      }

      const newCssConfig = {
        ...config.css,
        modules: {
          ...config.css?.modules,
          generateScopedName: sanitizeModuleClassname,
        },
      };

      return {
        ...config,
        css: newCssConfig,
      };
    },
  };
}
Enter fullscreen mode Exit fullscreen mode

This plugin checks whether the generateScopedName setting for CSS modules is already configured. If it is, the plugin throws an error to prevent conflicts. If not, it adds our sanitizeModuleClassname function to the configuration, ensuring that the class names now include the filename without the -module suffix.

Step 5: Using the Plugin

To use the plugin in your project, simply add it to your Vite plugin array:

import prettyModuleClassnames from './path-to-your-plugin';

export default {
  plugins: [prettyModuleClassnames()],
};
Enter fullscreen mode Exit fullscreen mode

Now, your project will generate more descriptive and informative class names for CSS modules, incorporating the filename and a unique hash.

Conclusion

Creating Vite plugins might seem daunting at first, but it's actually a fun and rewarding process. This example shows how easy it can be to customize Vite to suit your needs. Experiment with writing your own plugins, and you'll make your project even better!

If you found this guide helpful, don't forget to give a ⭐️ to the repository on GitHub! Your support is greatly appreciated and helps others discover the project.
Thank you!

Top comments (0)