携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情
- 本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
- 这是源码共读的第9期,链接:www.yuque.com/ruochuan12/…。
摘要
上回我们学习了使用 create-vue 来创建 vue 项目,创建出来的项目是基于 vite 的。而 vite 自然也有自己创建项目的方式,随着 vite3.0 的到来,我们一起学习它是如何创建 vue 项目的吧!
create-vite 初体验
和 create-vue 相比,create-vite 的选项就比较少了,就包括:
- 设置项目名称
- 选择框架模板
- 选择变体
接下来我们深入研究一下 create-vite 的源码吧
源码分析
vite 使用的是 pnpm 来管理的项目,我们的目标代码位于项目路径下的 packages\create-vite 文件夹。
以template- 开头的就是可供选择的项目模板了,官方默认提供了 6 种,算上 ts 版本那么就是 12 个模板,可供大家选择。
当然,还有社区模板,可以参考 awesome-vite
引入的包
fs,path 这是必须的了, 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 相差不大,具体的代码这里就不贴出来了,就总结下代码流程:
-
首先默认项目名称
vite-project; -
使用
prompts交互式地获取用户配置; -
已存在同名项目则清空,没有的话创建文件夹;
-
根据用户选择的模板复制相应的文件:
a. 非
package.json文件直接复制;b.
package.json文件的话先重写项目名称属性name, 然后复制; -
根据用户的包管理器,提示接下来的执行步骤。
总结
总体来说 create-vite 和create-vue 的流程是差不多的,create-vite 比 create-vue 多了很多项目模板,但是也少了很多可配置项,比如默认的模板就没有 vuex vue-router 以及测试相关的配置。
还有就是 create-vite 提供了很多的模板, 可供在直接下载,而 create-vue 是提供了很多模块的模板文件,然后根据用户的交互选择,来组装成用户需要的项目模板。