Steps to create a Vite project

Steps to create a Vite project

Preface

With the release and increasing stability of Vite2, more and more projects are now trying to use it. When we use Vite, we usually use the following commands to create a project:

// Using npm
npm init @vitejs/app
// Using yarn
yarn create @vitejs/app

 
// If you want to specify the project name and use a template for a specific framework, you can do it like this // npm
npm init @vitejs/app my-vue-app --template vue
//yarn
yarn create @vitejs/app my-vue-app --template vue

After running these commands, a project folder will be generated. For most people, it may be enough to create a project normally, but I am curious why a project folder will be generated when running these commands. Here we take yarn as an example to create a project.

What does yarn create do?

Many people may wonder why many projects are created using the yarn create command. In addition to Vite here, we create a React project in the same way: yarn create react-app my-app .
So what does this command do? It actually does two things:

yarn global add create-react-app
create-react-app my-app

For more information about yarn create, see here

Source code analysis

After yarn create @vitejs/app command is run, the code in @vitejs/create-app will be executed. Let's first look at the project structure of this file

The folders starting with template are all project templates for various frameworks and corresponding typescript versions. We don’t need to worry too much about them. The logic of creating a project is all in the index.js file. Let’s take a look at what’s done here

Project Dependencies

The first is the introduction of dependencies

const fs = require('fs')
const path = require('path')
const argv = require('minimist')(process.argv.slice(2))
const prompts = require('prompts')
const {
  yellow,
  green,
  cyan,
  blue,
  magenta,
  lightRed,
  red
} = require('kolorist')

fs and path are built-in modules of Nodejs, while minimist, prompts, and kolorist are third-party dependency libraries respectively.

  • minimist: is a tool for parsing command line arguments. document
  • prompts: is a command line interactive tool. document
  • kolorist: is a tool that makes command line output colorful. document

Template configuration

Next, the configuration files of different framework templates are generated, and finally an array of template names is generated.

// Here we only write the configuration of vue and react frameworks, the others are not much different, you can go to the source code if you are interested.
const FRAMEWORKS = [
  ......
  
  {
    name: 'vue',
    color: green,
    variants: [
      {
        name: 'vue',
        display: 'JavaScript',
        color: yellow
      },
      {
        name: 'vue-ts',
        display: 'TypeScript',
        color: blue
      }
    ]
  },
  {
    name: 'react',
    color: cyan,
    variants: [
      {
        name: 'react',
        display: 'JavaScript',
        color: yellow
      },
      {
        name: 'react-ts',
        display: 'TypeScript',
        color: blue
      }
    ]
  },
  
  ......
]

// Output template name list const TEMPLATES = FRAMEWORKS.map(
  (f) => (f.variants && f.variants.map((v) => v.name)) || [f.name]
).reduce((a, b) => a.concat(b), [])

Secondly, due to the particularity of the .gitignore file, a _gitignore file is created first under each framework project template, and then replaced with .gitignore when a project is created later. Therefore, an object will be pre-defined in the code to store the files that need to be renamed:

const renameFiles = {
  _gitignore: '.gitignore'
}

Utility Functions

Before we start talking about the core functions, let's take a look at the tool functions defined in the code. The most important are the three functions related to file operations.

copy

function copy(src, dest) {
  const stat = fs.statSync(src)
  if (stat.isDirectory()) {
    copyDir(src, dest)
  } else {
    fs.copyFileSync(src, dest)
  }
}

The copy function is used to copy the file or folder src to the specified folder dest. It will first get the status stat of src. If src is a folder, that is, stat.isDirectory() is true, it will call the copyDir function introduced below to copy the files in the src folder to the dest folder. On the contrary, if src is a file, the fs.copyFileSync function is directly called to copy the src file to the dest folder.

copyDir

function copyDir(srcDir, destDir) {
  fs.mkdirSync(destDir, { recursive: true })
  for (const file of fs.readdirSync(srcDir)) {
    const srcFile = path.resolve(srcDir, file)
    const destFile = path.resolve(destDir, file)
    copy(srcFile, destFile)
  }
}

The copyDir function is used to copy files in a folder srcDir to the specified folder destDir. It will first call the fs.mkdirSync function to create the specified folder, then call fs.readdirSync to get the files from the srcDir folder and traverse and copy them one by one; finally, it calls the copy function to copy. Recursion is used here because there may be files or folders in the folder.

emptyDir

function emptyDir(dir) {
  if (!fs.existsSync(dir)) {
    return
  }
  for (const file of fs.readdirSync(dir)) {
    const abs = path.resolve(dir, file)
    if (fs.lstatSync(abs).isDirectory()) {
      emptyDir(abs)
      fs.rmdirSync(abs)
    } else {
      fs.unlinkSync(abs)
    }
  }
}

The emptyDir function is used to clear the code under the dir folder. It will first determine whether the dir folder exists. If it does, it will traverse the files in the folder and construct the file's path abs. When abs is a folder, it will recursively call the emptyDir function to delete the files in the folder, and then call fs.rmdirSync to delete the folder; when abs is a file, it will call the fs.unlinkSync function to delete the file.

Core Functions

Next is the init function that implements the core functionality.

Command line interaction and creating folders

The first step is to get the command line parameters

let targetDir = argv._[0]
let template = argv.template || argv.t

const defaultProjectName = !targetDir ? 'vite-project' : targetDir

argv._[0] represents the first parameter after @vitejs/app
template is the name of the template to be used
defaultProjectName is the name of the project we created.
The next step is to use the prompts package to output the query in the command line, like this:

The specific code is as follows:

// Some codes about command line interaction are not all put here. If you are interested, you can go to the source code let result = {}

result = await prompts(
  [
    {
      type: targetDir ? null : 'text',
      name: 'projectName',
      message: 'Project name:',
      initial: defaultProjectName,
      onState: (state) =>
        (targetDir = state.value.trim() || defaultProjectName)
    },
    ......
    
  ]
)

const { framework, overwrite, packageName, variant } = result

const root = path.join(cwd, targetDir)

if (overwrite) {
  emptyDir(root)
} else if (!fs.existsSync(root)) {
  fs.mkdirSync(root)
}

template = variant || framework || template

// Output project folder path console.log(`\nScaffolding project in ${root}...`)

const templateDir = path.join(__dirname, `template-${template}`)

After the selection is completed, the result of our selection will be returned
root is the full file path constructed by the path.join function
overwrite is for when there is already a file with the same name that we want to create, whether to overwrite it. If overwriting, call the previous emptyDir function to empty the folder. If the folder does not exist, call fs.mkdirSync to create the folder
templateDir The name of the template folder selected

Writing to a File

const write = (file, content) => {
  const targetPath = renameFiles[file]
    ? path.join(root, renameFiles[file])
    : path.join(root, file)
  if (content) {
    fs.writeFileSync(targetPath, content)
  } else {
      copy(path.join(templateDir, file), targetPath)
  }
}

const files = fs.readdirSync(templateDir)
for (const file of files.filter((f) => f !== 'package.json')) {
  write(file)
}

const pkg = require(path.join(templateDir, `package.json`))

pkg.name = packageName

write('package.json', JSON.stringify(pkg, null, 2))

const pkgManager = /yarn/.test(process.env.npm_execpath) ? 'yarn' : 'npm'

// Output some prompts to tell you that the project has been created, and tell you the command you need to run to start the project next console.log(`\nDone. Now run:\n`)
if (root !== cwd) {
console.log(` cd ${path.relative(cwd, root)}`)
}
console.log(` ${pkgManager === 'yarn' ? `yarn` : `npm install`}`)
console.log(` ${pkgManager === 'yarn' ? `yarn dev` : `npm run dev`}`)
console.log()

The write function accepts two parameters file and content, and has two functions:

  • Write the specified content content to the specified file file and call the fs.writeFileSync function to write the content to the file.
  • Copy the files in the template folder to the specified folder, and call the copy function introduced earlier to copy the files.

Then call fs.readdirSync to read the files in the template folder, traverse and copy them one by one to the project folder (the package.json file to be filtered because the name field in it needs to be modified); finally write to the package.json file.

summary

The implementation of Vite's create-app package has only about 320 lines of code, but it takes into account the compatibility of various scenarios; after learning it, it is not difficult to implement such a CLI tool by yourself.

This is the end of this article about the implementation steps of Vite project creation. For more relevant Vite project creation content, please search 123WORDPRESS.COM's previous articles or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Detailed explanation of vite2.0+vue3 mobile project
  • Detailed explanation of Vue3.0 + TypeScript + Vite first experience
  • Detailed explanation of vite+ts to quickly build vue3 projects and introduce related features
  • Detailed explanation of vite2.0 configuration learning (typescript version)
  • vite2.x implements on-demand loading of ant-design-vue@next components
  • How to build a React project with Vite
  • Steps to build the vite+vue3+element-plus project
  • Vue3.0+vite2 implements dynamic asynchronous component lazy loading
  • Implementation of vite+vue3.0+ts+element-plus to quickly build a project

<<:  MySQL Workbench download and use tutorial detailed explanation

>>:  MySQL5.7+ MySQL Workbench installation and configuration method graphic tutorial under MAC

Recommend

Example of implementing login effect with vue ElementUI's from form

Table of contents 1. Build basic styles through E...

Advantages and disadvantages of common MySQL storage engines

Table of contents View all storage engines InnoDB...

Vue implements graphic verification code

This article example shares the specific code of ...

Implement full screen and monitor exit full screen in Vue

Table of contents Preface: Implementation steps: ...

The concrete implementation of JavaScript exclusive thinking

In the previous blog, Xiao Xiong updated the meth...

Command to remove (delete) symbolic link in Linux

You may sometimes need to create or delete symbol...

Do you know what are the ways to jump routes in Vue?

Table of contents The first method: router-link (...

Example of how to check the capacity of MySQL database table

This article introduces the command statements fo...

MySQL spatial data storage and functions

Table of contents 1. Data Type 1. What is MySQL s...

Definition and usage of MySQL cursor

Creating a Cursor First, create a data table in M...

jQuery implements nested tab function

This article example shares the specific code of ...