- 本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
- 这是源码共读的第37期,链接:juejin.cn/post/712519…
前言
这是我第一次在掘金写源共读文章,希望大家一起来参加学习写文章
1.准备源码
//源码地址
https://github.com/vitejs/vite/blob/HEAD/packages/create-vite/index.js
//复制一份代码到自己的仓库
git clone https://github.com/vitejs/vite.git
//安装依赖
pnpm i
//然后找到packages目录下的create-vite的index.js开始学习源码
2.学习源码
用到的库
import fs from 'node:fs' //文件操作
import path from 'node:path' //路径操作
import {
fileURLToPath
} from 'node:url' //将文件URL解码为路径字符串
import minimist from 'minimist' // 解析命令行参数
import prompts from 'prompts' // 询问选择
import {
blue,
cyan,
green,
lightRed,
magenta,
red,
reset,
yellow
} from 'kolorist' // 终端颜色输出
formatTargetDir 利用正则将反斜杠/替换 为空字符串
function formatTargetDir(targetDir) {
return targetDir ? targetDir.trim().replace(/\/+$/g, ''):''}
getProjectName 获取项目名称
- path.resolve() 当前目录的绝对路径
- path.basename() 最后一截路径
const getProjectName = () =>
targetDir === '.' ? path.basename(path.resolve()) : targetDir
询问项目名、选择框架,选择框架变体等
try {
result = await prompts(
[{
type: targetDir ? null : 'text',
name: 'projectName',
message: reset('Project name:'),
initial: defaultTargetDir,
onState: (state) => {
targetDir = formatTargetDir(state.value) || defaultTargetDir
}
},
....
创建文件夹
const root = path.join(cwd, targetDir)
if (overwrite) {
//如果当前目录出现相同名字的输出目录并选择了覆盖,则清空文件夹内的文件
emptyDir(root)
} else if (!fs.existsSync(root)) {
// 新建文件夹
fs.mkdirSync(root, {
recursive: true
})
}
获取模板文件
// determine template 选择的项目模板
template = variant || framework || template
const templateDir = path.resolve(
fileURLToPath(
import.meta.url),
'..',
`template-${template}`
)
写入文件和项目名
//写入文件函数
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 = JSON.parse(
fs.readFileSync(path.join(templateDir, `package.json`), 'utf-8')
)
//把项目名称写入package.json
pkg.name = packageName || getProjectName()
write('package.json', JSON.stringify(pkg, null, 2))
安装完提示
// 打印安装完成后的信息,用哪个包管理器就提示哪个包管理器的运行命令
const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent)
const pkgManager = pkgInfo ? pkgInfo.name : 'npm'
console.log(`\nDone. Now run:\n`)
if (root !== cwd) {
console.log(` cd ${path.relative(cwd, root)}`)
}
switch (pkgManager) {
case 'yarn':
console.log(' yarn')
console.log(' yarn dev')
break
default:
console.log(` ${pkgManager} install`)
console.log(` ${pkgManager} run dev`)
break
}
3.流程总结
- 根据输入项目名称创建目录,如果已存在改目录,提示是否覆盖
- 根据选择的项目模板及变体(ts)读取对应的框架模板写入到项目名称目录,重写package.json的项目名称
- 使用了哪个包管理器创建项目,那么就输出 npm/yarn/pnpm 相应的命令提示运行