Vite初始化项目之原理揭秘

484 阅读3分钟

本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。这是源码共读的第37期,链接: juejin.cn/post/712908…

我们使用vite初始化项目的时候,首先在命令行中输入相应的命令,然后进行简单的交互,过一会儿一个项目就建好了。您是否了解这背后的原理呢?阅读本文一起学习吧!

1.准备工作

首先clone vite的代码:

git clone  https://github.com/vitejs/vite.git

然后在packages中找到create-vite

2.源码解读

2.1 确定入口文件

读源码第一步是找到入口文件, 根据package.json的bin选项可以知道执行create-vite命令时会执行index.js文件,所以index.js文件就是入口文件。

2.2 create-vite 执行流程

index.js文件的源码行数不到400,整体逻辑清晰易懂,这里只总结了其执行流程和一些关键代码供参考。如果您想详细了解对其源码的分析可以阅读本文最后的参考资料。

可以结合下图来理解上面的流程:

2.3 create-vite关键代码

2.3.1 copy拷贝文件到目录

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

fs.statSync获取文件信息,然后判断是文件还是目录。如果是目录则使用copyDir拷贝目录中的文件;如果是文件则使用fs.copyFileSync方法拷贝文件。

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

目标目录不一定存在,所以要新建目录。然后针对源目录的每个文件都要使用path.resolve计算其路径,同理计算目标文件的路径,然后调用copy方法。

2.3.3 isEmpty判断文件夹是否为空文件夹

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

使用fs.readdirSync读取文件夹,返回值为文件数组,数组长度为0或者长度为1但是只有.git文件,那么这个文件夹可以认为是空文件夹。

2.3.4 emptyDir将文件夹清空

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

如果目录不存在则返回,否则循环遍历目录中的每一个文件或者目录进行递归强制删除。

3.总结

create-vite 中对于命令参数解析用到了命令行解析工具minimist;和使用者交互确定项目名称和类型用到了交互式命令行提示工具prompts;为了使命令行输出信息更加美观醒目则使用了kolorist这款命令行颜色工具。

create-vite涉及到了大量的文件相关操作,例如文件的读写以及文件夹的创建和删除,这些功能的实现则借助了node.js fs 模块相关的API; 另外涉及到文件的路径的确定则使用到了path模块和url模块的API。

三方npm包


Node API

4.收获

第一,了解使用vite创建项目的原理;

第二,学习到node.js重要API的使用方法;

第三,积累了有用的npm包。

参考资料

【1】juejin.cn/post/712519…

【2】juejin.cn/post/712953…

【3】juejin.cn/post/712985…