【第9期 · 续】create-vite —— 使用 vite 构建 vue 项目

164 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情

摘要

上回我们学习了使用 create-vue 来创建 vue 项目,创建出来的项目是基于 vite 的。而 vite 自然也有自己创建项目的方式,随着 vite3.0 的到来,我们一起学习它是如何创建 vue 项目的吧!

create-vite 初体验

image.png

create-vue 相比,create-vite 的选项就比较少了,就包括:

  1. 设置项目名称
  2. 选择框架模板
  3. 选择变体

接下来我们深入研究一下 create-vite 的源码吧

源码分析

vite 使用的是 pnpm 来管理的项目,我们的目标代码位于项目路径下的 packages\create-vite 文件夹。

image.png

template- 开头的就是可供选择的项目模板了,官方默认提供了 6 种,算上 ts 版本那么就是 12 个模板,可供大家选择。

image.png

当然,还有社区模板,可以参考 awesome-vite

引入的包

fspath 这是必须的了, create-vite 同样也使用了如下三个包:

minimist 是一个用于处理命令行调用node指令时,处理node之后的一系列参数的模块。

prompts 轻量级、美观、用户友好的交互式提示。

kolorist 给控制台输入内容上色。

看来这三个包是做命令行交互脚本的三剑客啊。

import fs from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import minimist from 'minimist'
import prompts from 'prompts'
import {
  blue,
  cyan,
  green,
  lightRed,
  magenta,
  red,
  reset,
  yellow
} from 'kolorist'

基本参数

获取命令行参数;获取当前路径;模板对象;

值得学习的是通过map reduce 的组合,获取全部的模板名字。

const argv = minimist(process.argv.slice(2), { string: ['_'] })
const cwd = process.cwd()

const FRAMEWORKS = [
  {
    name: 'vanilla',
    color: yellow,
    variants: [
  {
    name: 'vue',
    color: green,
    variants: [
    ...
      {
        name: 'vue',
        display: 'JavaScript',
        color: yellow
      },
      {
        name: 'vue-ts',
        display: 'TypeScript',
        color: blue
      }
    ]
  },
  ...
]

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

辅助函数

源码中遇到了一些辅助函数,分别介绍一些它们的作用。

formatTargetDir 格式化 targetDir

function formatTargetDir(targetDir) {
  return targetDir?.trim().replace(/\/+$/g, '')
}

递归地复制文件。

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

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)
  }
}

判断项目名是否合法,并将不合法的项目名转换成合法的。

function isValidPackageName(projectName) {
  return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(
    projectName
  )
}

function toValidPackageName(projectName) {
  return projectName
    .trim()
    .toLowerCase()
    .replace(/\s+/g, '-')
    .replace(/^[._]/, '')
    .replace(/[^a-z0-9-~]+/g, '-')
}

判断文件是否已存在

function isEmpty(path) {
  const files = fs.readdirSync(path)
  return files.length === 0 || (files.length === 1 && files[0] === '.git')
}

清空文件夹内容

function emptyDir(dir) {
  if (!fs.existsSync(dir)) {
    return
  }
  for (const file of fs.readdirSync(dir)) {
    fs.rmSync(path.resolve(dir, file), { recursive: true, force: true })
  }
}

关键源码分析

具体的源码逻辑跟create-vue 相差不大,具体的代码这里就不贴出来了,就总结下代码流程:

  1. 首先默认项目名称 vite-project

  2. 使用prompts 交互式地获取用户配置;

  3. 已存在同名项目则清空,没有的话创建文件夹;

  4. 根据用户选择的模板复制相应的文件:

    a. 非 package.json 文件直接复制;

    b. package.json 文件的话先重写项目名称属性name, 然后复制;

  5. 根据用户的包管理器,提示接下来的执行步骤。

总结

总体来说 create-vitecreate-vue 的流程是差不多的,create-vitecreate-vue 多了很多项目模板,但是也少了很多可配置项,比如默认的模板就没有 vuex vue-router 以及测试相关的配置。 还有就是 create-vite 提供了很多的模板, 可供在直接下载,而 create-vue 是提供了很多模块的模板文件,然后根据用户的交互选择,来组装成用户需要的项目模板。