Make Your First Vite Plugin

A guide on how to make a simple Vite plugin

Sang Nguyen
JavaScript in Plain English

--

Photo by Josh Withers on Unsplash

Vite is an incredible build tool for modern web projects. Besides basic configuration, Vite also lets us do more things with third-party plugins. In this article, I’ll show you one of the most straightforward ways to write a Vite plugin.

What is the plugin we will do?

Before starting to build a Vite plugin, I’ll talk a bit about the main feature of this plugin. Do you know CNAME? If you don’t know, you may take a look here.

Somewhere we need to create a CNAME file to make our custom domain work. It means the “dist” or “build” directory needs to contain this file. In the Vite project, we can do it easily by creating the CNAME file in the “public” directory. But because we need to do a Vite plugin in this article, so I’ll choose this topic for our plugin. With this plugin, we can generate the CNAME file automatically, just need to define a domain in vite.config.js . Besides no need to create a file, this plugin allows users to put some logic to define a domain name are conditions, environment…

Create a Vite project

I think we will start with a basic step — creating a Vite project. We have many ways to create a Vite project. In this article, I’ll use one of the simplest ways by the yarn create command. I’ll create a Vite project with a React template (you can use Vue, other templates, or no template). I’ll run this command with React template to create a Vite project:

yarn create vite vite-plugin --template react

Here is the project created by this command:

We may see the plugin list in avite.config.js file. We already have the react plugin that is added. We will create a new plugin and add it to this list like this. Let’s run the build command to see the result by the yarn build command.

As you see, we will get the directory “dist” which contains all of the project’s output files. Our plugin's mission is to create a CNAME file in this directory automatically in the build process. Let’s do it!

Let’s create our plugin

In this step, we will look around at the way and the basic principle to make a Vite plugin. Based on the Vite document, we may see that a Vite plugin format is an object. In this object, we may define our plugin action. But Vite also recommends that we should create a factory function that returns the actual plugin object instead of a plain object. Because the function can accept options allowing users to customize the plugin's behavior. So in this article, I’ll define our plugin as a factory function. I’ll create our plugin in the file “viteCNAMEPlugin.js” in the root. Here is its source code:

To use this plugin, we just need to add it to the plugin array in vite.config.js.

I’ll run the yarn build command again. Let’s the result:

It runs successfully. In the next step, we will work with “the hooks” in Vite plugin development.

Play with the hook to implement our action

In the previous part, we have known that the Vite plugin is defined as an object. In this part, we will work with this object. Firstly, we need to know about the “build hooks” in Vite.

Every time we run the build command, Vite runs many steps to complete this process. Each step has its mission (Ex: Preparing to build, loading config, building, bundling…). Vite provides us build hooks, which correspond to the build step in the build process. Through these hooks, we can add our actions to the build process. Here is an example picture of it:

In Vite, we have Universal Hooks and Vite Specific Hooks. In this article, we will work with two hooks from both Universal Hooks and Vite Specific Hooks.

About Universal Hooks, the Vite document written like that

During dev, the Vite dev server creates a plugin container that invokes Rollup Build Hooks the same way Rollup does it.

It means we may follow build hooks from Rollup.js to define our action. You may take a look at this page:

In our plugin, I’ll use the hook “writeBundle” to generate the CNAME file. I choose this hook because this is the last hook of the output generation phase. I think it is a nice phase to generate our CNAME file. To do that, we just need to add a new property in our object plugin. A property name is “writeBundle” and a property value is a function. In this function, we will create a CNAME file in the build directory. It’s so easy to do, here is my plugin source code after we added this property:

It’s a simple function. Its mission just is to create a new file in the location “./dist/CNAME” as the content is a value from “domain”. Let’s test it!

It worked well! The CNAME file with content “sangnguyen.dev” is created in the dist directory. I think we hit our target in this article. We have created a plugin that allows users can create the CNAME file automatically. But do you remember what I said above? I said we will work with both Universal Hooks and Vite Specific Hooks. Currently, we just work with only one hook “writeBundle” from Universal Hooks. In the next part, we will work with a Vite Specific hook.

Optimize our plugin with the configResolved hook

In the title of this part, I mention the “configResolved” hook. It is one of Vite Specific Hooks. But before playing with this hook, we will talk about the bad things about our plugin. In our plugin, we fixed the build directory as “dist”. It will be a problem if the user changes the outDir . Let’s see this demo here:

As you see, the problem is happening. After the build command is completed, we have two directories. One is the output code. One is the “dist” directory which only contains the CNAME file. We have many ways to solve this problem. One of them is to add one more option to our plugin. This option will define the out directory location. But I don’t really like this solution. So I recommend you another solution. This is to use the “configResolved” hook to get the build config values.

The “configResolved” hook is a function with a parameter. This parameter value is a “resolvedConfig”. Based on the Vite document, we just need to create a global variable and assign the config value to this variant in this hook. Then we can access the config values in other hooks. Let’s see the changes:

We created a new global variable viteConfig . In the “configResolved” hook, we just need to assign the parameter to the viteConfig variable. Then we can access the build dist from viteConfig in the path viteConfig.build.outDir . Let’s test it:

We have three cases to test. The first case is a normal case. The second case is the build dist from the command. The last case is the build dist from the vite.config.js file. It worked well in all three cases. I think we can “finish” our plugin in this part.

Conclusion

Vite is a modern build tool. I think it will grow up more in the future. I hope this article will give you some useful information. With them, you can make your own Vite plugins. This is the full source code of our demo in Github:

Besides things I shared in this article, there are some links I recommend you should read.

Thanks for reading. Again, I hope this article will be helpful to you.

Photo by Kim Hanh Do on Unsplash

Contact me via LinkedIn or Twitter.

More content at PlainEnglish.io. Sign up for our free weekly newsletter. Follow us on Twitter, LinkedIn, YouTube, and Discord. Interested in Growth Hacking? Check out Circuit.

--

--