In Search for A Better Vue.js Project Template (Part I)

Today, to start a Vue 3 project, you can simply run npm init [email protected] in the command line.

You’ll then go through a few prompts. After choosing what features you’d like to include, a new project will be ready in seconds.

It’s so smooth and straightforward.

So, what’s the magic here?

the create-vue package

npm has the npm init <initializer> command that will automatically download a corresponding create-<initializer> package and execute it.

We believe it'll be the easiest way for one to run a project scaffolder as npm is available on most front-end developer’s machines

Only one caveat: remember to add a version string after the initializer name (like [email protected]); otherwise, npm may end up using a cached outdated version of the package.

As npm downloads create-vue on the fly, we would like to make it as small as possible to speed up the downloading process. So, firstly, we use as few third-party dependencies as possible. They need to be lightweight, too. In the end, create-vue uses only 3 dependencies: minimist for simple command-line argument parsing, prompts for the interactive prompts, and kolorist for output colorization.

Then, we use esbuild to bundle and tree-shake these dependencies. By doing so, we can skip the package resolving process for these dependencies. Not only does it reduce network traffic, but it also avoids the request waterfall.

The result is quite satisfying: executing npm init [email protected] only costs less than 100KB in 2 requests (one resolves the latest version, the other downloads the package tarball). Much smaller than the size of an average web page in 2021.

It even supports offline mode:

npm init [email protected] --prefer-offline could work after the network connection is lost, as long as you’ve previously run npm init [email protected] successfully.

the folder structure

Let’s start with the bare-bone project template (Choosing “No” for every question or npm init [email protected] -- --default):

image description

Note: you can see all the possible outcomes of different combinations of choices at


We choose Vite as the default dev server and bundler for new Vue projects, because we believe it provides the best out-of-box experience.

Vite is framework-agnostic. So for a Vue project, we need to enable the vue plugin in the configuration file. Thus the vite.config.js file.

@vitejs/plugin-vue-jsx is an opt-in choice, though. Because the plugin depends on babel, thus would slow down the dependency installation and project compilation a little. It should only be added when necessary.

Aliases - we’ll talk about that in a later article.

public/ directory

The public directory is for static files, those whose URLs won’t change after bundling.


In Vite, index.html serves as the entry point of the application, so it is in the root directory instead of public/.

With a few extra keystrokes, you are also able to set up a multi-page app with multiple .html entry points in Vite:

src/ directory

src/ is where the project source code lives.

Previously in Vue CLI, this directory is mandatory, otherwise, you may run into issues with all kinds of plugins.

In Vite, it is no longer mandatory because source code entries are specified in the index.html as script type="module" src="./src/main.js".

But we still strongly recommend you to keep putting all project source code inside src/.

A shared convention in the community would be easier for tooling and knowledge sharing.

__tests__/ sub-directories

If you answer yes to “Add Vitest for testing” or “Add Cypress for testing”, you will see a __tests__/ directory inside src/components.

Inside that directory is a HelloWorld.spec.ts file, which contains test cases for the HelloWorld.vue component.

Unit tests, unlike end-to-end tests, are often testing specific components or modules. Therefore it makes more sense to put them alongside their corresponding source files.

Meanwhile, we don’t want them to be too conspicuous when viewing the project’s folder structure, so we put them in a sub-directory instead of listing directly.

Some rights reserved
Except where otherwise noted, content on this page is licensed under a Creative Commons Attribution-ShareAlike 4.0 International license.