Starting a Vue Project with Vite

This post will look at starting a new Vuejs project using the Vite frontend toolchain.

What is Vite?

In short, Vite (The French word for fast) is similar to tools such as vue-cli, but it is framework agnostic and much faster. Why?

Vite relies on modern JavaScript features such as Ecmascript modules (ESM) and the esbuild bundler. When we write our code using ESM the bundler no longer needs to do all the processing it had to do when our source code was written using Asynchronous Module Definition (AMD) or Commonjs.

With ESM, Vite will send our entry point file linked to in the HTML to the browser as-is. For example:

<script type="module" src="./main.js"></script>

The browser will then make separate HTTP requests (if applicable) for each import statement (our dependencies) inside this entry file. The Vite dev-server will respond to these requests without any processing before the response, providing instantaneous updates to the page as you write your code. Hot updates also apply to CSS, further improving your developer experience and productivity. All of this is available even as our codebase grows. I'll let Even You take it from here.

https://www.youtube.com/watch?v=DkGV5F4XnfQ

Prerequisites

Before starting with Vite, you must have Node.js installed on your machine. This also includes npm, which we will use in our next step.

Getting Started with Vite

As mentioned earlier, Vite is framework agnostic. In this post, however, we will use it to start a new Vue project using the provided Vue project template. We will be using npm, but you can achieve the same result using Yarn or pnpm.

Note: You can determine the installed npm version by running npm -v

# npm 6.x
npm create vite@latest getting-started --template vue

# npm 7+ - note the extra double-dash (--)
npm create vite@latest getting-started -- --template vue

Once you run the above command, you will see output similar to the following:

Scaffolding project in ...

Done. Now run:

cd getting-started
npm install
npm run dev

Once the dev command completes, open the provided URL in your browser. You should see a page with the Vite and Vuejs logos, links, and additional information.

What did Vite do?

Vite created a new Vuejs project with a basic structure and scaffolding. Let’s look at some of the files that were added to the project.

Vite config

You will find the Vite config file at the project's root.

// vite.config.js
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
});

All the config currently does is enable support for Vue through the Vue plugin. There is one additional piece of configuration I recommend. Change your configuration to match the following:

import path from "path";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

// https://vitejs.dev/config/
export default defineConfig({
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "src"),
    },
  },
  plugins: [vue()],
});

This allows you to use the following syntax when importing resources and components.

import MyModule from "@/components/atoms/MyComponent.vue";

As you might infer from the configuration entry, the @ symbol will always resolve to the root of the src directory. This means that no matter where in the source tree your component is, you can always use @ to refer to src and then resolve the rest from there. This helps situations such as these:

import MyComponent from "../../../components/atoms/MyComponent.vue";

This also means you can copy and paste resources from any file to any other file and the path will resolve successfully.

Package scripts

Vite created some script targets in the package.json file. These are clear and understandable, so I will briefly touch on them. While developing locally, you will start the development server using npm run dev. When deploying to production, you will specify the npm run build script as the command to execute. This will build the production-ready assets in the dist folder, which would be the directory that your host serves.

If you want to preview a production build locally, you will run npm run preview.

Source files

Our entry point

You will also find the index.html file at the project's root, essentially our entry point. This file is minimal in nature, and most of this file should be familiar to you. There are three items to call out here.

<link rel="icon" type="image/svg+xml" href="/vite.svg" />

This image will be used as the favicon in browsers that support using an SVG for this purpose. The other interesting topic to address here is where this file is located. The vue.svg is located in src/assets, and the vite.svg file is located in the public folder at the project's root.

Here is the purpose of the public folder according to the docs:

If you have assets that are:

  • Never referenced in source code (e.g. robots.txt)
  • Must retain the exact same file name (without hashing)
  • ...or you simply don't want to have to import an asset first just to get its URL

Then you can place the asset in a special public directory under your project root.

I would say the reason why the vite.svg is placed inside public here, even though it is referenced in the source, is related to the second bullet point. If it were placed inside the assets folder, it would have a hashed file name, and the reference in the index.html file would not succeed and result in a 404 error.

The app container element

<div id="app"></div>

This is the container for our Vue app. If you open main.js inside the src directory, you will see this line:

createApp(App).mount("#app");

We create our App instance and then mount it inside our app container referenced by the id of app.

Our JavaScript entry point

The last point of interest is the following line:

<script type="module" src="/src/main.js"></script>

As the code suggests, this imports the main.js file we just looked at. It also identifies this to be of a module type. This means that Vite will expect our source code to be written using ESM, as discussed earlier in this post.

The src directory

We have already briefly examined the main.js file inside the src directory. We won't be examining the details of each file here, but rather getting a basic understanding. At the top of the src directory is our assets directory.

Unlike assets saved in the public directory, assets saved in this directory will get hashed filenames, be part of the build assets graph, and can be processed by plugins for optimization. There are several other topics to keep in mind so it is a good idea to read the official docs.

The next directory is the components directory. It is a convention in Vue projects to place all of your individual components within this components folder and, from there, follow their recommended file naming conventions.

App.vue is our parent (or grandparent 😁) component. From here, we will import our top-level components. In this case, the one component we import is the HelloWorld.vue component from our components directory.

You will notice that it is imported as follows:

import HelloWorld from "./components/HelloWorld.vue";

Nothing wrong with that, but if you added the additional configuration mentioned earlier, you can import the component as follows:

import HelloWorld from "@/components/HelloWorld.vue";

The remaining file in our src directory is the style.css file. This contains our global, non-scoped styles and is imported inside main.js. The classes and rules defined here will apply and is available to the entire application.

The .vscode directory

The contents of this directory will only be of interest if you use the VSCode editor. Here is a single extensions.json file with an array of recommendations. This lists (at the time of writing) two recommended extensions by the Vue team. The Volar extension is highly recommended while the second recommendation will mostly be useful to you if you are using TypeScript or TypeScript annotations.

Build assets

Before we end this post, let us take a quick look at what happens when we run the production build script. In your terminal, execute the following command.

npm run build

You should see the output in your terminal similar to the following.

vite v4.0.3 building for production...
✓ 16 modules transformed.
dist/index.html                  0.45 kB
dist/assets/vue-5532db34.svg     0.50 kB
dist/assets/index-2a0f3dfe.css   1.29 kB │ gzip:  0.66 kB
dist/assets/index-bca36975.js   54.21 kB │ gzip: 21.89 kB

In the newly created dist directory, you will find our index.html file. When you open this file, you will notice two differences to our index.html at the project’s root.

<script type="module" crossorigin src="/assets/index-bca36975.js"></script>
<link rel="stylesheet" href="/assets/index-2a0f3dfe.css">

Our script tag has been hoisted into the head of the document. Vite has also added a crossorigin attribute and updated the name of the JavaScript file based on its new hashed filename. It also now includes a hashed style.css file containing all of our CSS style rules.

The JavaScript file contains all of the JavaScript that makes up our current single-page website. You will also notice that the vue.svg file has been added here, but the file name is also hashed. This then is everything that is needed to serve our webpage to end-users. In total, this makes up ~24 kilobytes (kb) of data transferred to our end-users.

This number is small at the moment but will grow and is something we need to keep a close eye on.

Conclusion

Vite is fast and easy to use, enhances the developer experience, and generally produces smaller bundle sizes than other build tools. I hope that you have found this introduction to Vite useful and that, the next time you start a Vue project, you will give Vite a try.