創(chuàng)建項目及包管理yarn create vite源碼學習
1.引言
我們在編程學習的過程中也會寫一些項目的模板,這樣的模板在后期其實并沒有進行很好的管理,以至于下次再來回顧或使用的時候還需要從“零”開始,在使用過 Vite 來創(chuàng)建項目后順便拿看了一下倉庫中create-vite包中的源碼,得到了很好的啟發(fā)~
2.走進“yarn create vite”的源碼
2.1 Vite 創(chuàng)建項目的方式:
- 終端交互方式創(chuàng)建項目;
- 終端指定模版創(chuàng)建項目;
2.1.1 終端交互方式創(chuàng)建項目:
相比于以往的 CLI 工具提供的創(chuàng)建項目都需要優(yōu)先手動安裝 CLI 工具后再執(zhí)行對應的創(chuàng)建命令,另一種就是 Vite 目前采用的直接通過包管理器內(nèi)置命令使用統(tǒng)一的規(guī)范來實現(xiàn)項目的快速創(chuàng)建;
如果你使用 YARN:
# yarn yarn create vite
接下來就可以按終端提示進行項目名稱的錄入和項目模板的選擇了~
2.1.2 終端指定模版創(chuàng)建項目:
如果我們很明確內(nèi)置的模板選項的話我們可以在終端執(zhí)行時同時錄入項目名稱和模板名稱更快速的創(chuàng)建項目;
# yarn yarn create vite my-vue-app --template vue
備注:使用“.”來在當前目錄創(chuàng)建項目;
2.2 源碼分析:
- 終端參數(shù)解析;
- 交互收集數(shù)據(jù);
- 目錄初始化;
- 拷貝模板文件夾;
- 重寫
gitignore名稱; - 重寫
package字段; - 后續(xù)操作提示;
2.2.1 終端參數(shù)解析:
通過 minimist 模塊將終端參數(shù)解析為對象形式:
const argv = minimist<{
t?: string
template?: string
}>(process.argv.slice(2), { string: ['_'] })
通過讀取對象屬性來得到 argTargetDir 和 argTemplate 兩個參數(shù):
const argTargetDir = formatTargetDir(argv._[0]) const argTemplate = argv.template || argv.t
2.2.2 交互收集數(shù)據(jù):
通過交互收集的數(shù)據(jù)包括:projectName、overwrite、packageName、framework、variant:
projectName:默認值是 defaultTargetDir ,對應的值是vite-project,當通過終端解析到 argTargetDir 后將跳過此步驟;
{
type: argTargetDir ? null : 'text',
name: 'projectName',
message: reset('Project name:'),
initial: defaultTargetDir,
onState: (state) => {
targetDir = formatTargetDir(state.value) || defaultTargetDir
}
}
overwrite:在確認好 targetDir 參數(shù)后,我們要看 targetDir 對應的文件夾是否存在或是文件夾中是否有文件,要提示用戶是否需要情況或終端操作;
{
type: () =>
!fs.existsSync(targetDir) || isEmpty(targetDir) ? null : 'confirm',
name: 'overwrite',
message: () =>
(targetDir === '.'
? 'Current directory'
: `Target directory "${targetDir}"`) +
` is not empty. Remove existing files and continue?`
},
{
type: (_, { overwrite }: { overwrite?: boolean }) => {
if (overwrite === false) {
throw new Error(red('?') + ' Operation cancelled')
}
return null
},
name: 'overwriteChecker'
}
packageName:packageName 的值通過 路徑 和 targetDir 來確定,在終端交互收集數(shù)據(jù)的時候需要對值做格式的校驗來確定合法性;
// 確定項目名稱
const getProjectName = () =>
targetDir === '.' ? path.basename(path.resolve()) : targetDir
// 校驗項目名稱合法性
{
type: () => (isValidPackageName(getProjectName()) ? null : 'text'),
name: 'packageName',
message: reset('Package name:'),
initial: () => toValidPackageName(getProjectName()),
validate: (dir) =>
isValidPackageName(dir) || 'Invalid package.json name'
}
framework:如果終端已獲取到 argTemplate 參數(shù),且已內(nèi)置該模板將跳過這步,否則將進行預置模板配置的解析并選擇;
{
type:
argTemplate && TEMPLATES.includes(argTemplate) ? null : 'select',
name: 'framework',
message:
typeof argTemplate === 'string' && !TEMPLATES.includes(argTemplate)
? reset(
`"${argTemplate}" isn't a valid template. Please choose from below: `
)
: reset('Select a framework:'),
initial: 0,
choices: FRAMEWORKS.map((framework) => {
const frameworkColor = framework.color
return {
title: frameworkColor(framework.display || framework.name),
value: framework
}
})
}
variant:通過上一步得到的 framework 參數(shù)將確定這個步的配置,因為同樣的 framework 看一配置多種 variant ;
{
type: (framework: Framework) =>
framework && framework.variants ? 'select' : null,
name: 'variant',
message: reset('Select a variant:'),
choices: (framework: Framework) =>
framework.variants.map((variant) => {
const variantColor = variant.color
return {
title: variantColor(variant.display || variant.name),
value: variant.name
}
})
}
2.2.3 目錄初始化:
目錄如果不存在的話我們需要創(chuàng)建對應的目錄,因為在前期收集參數(shù)可能是個目錄,這兒創(chuàng)建的時候需要遞歸創(chuàng)建,但是當目錄存在且有內(nèi)容的時候我們就需要清空掉里面的文件了,但是在清空的時候我們要考慮當時目錄可能已經(jīng)被版本管理過了,所以需要對.git目錄過濾掉,這樣才更完整;
const root = path.join(cwd, targetDir)
if (overwrite) {
emptyDir(root)
} else if (!fs.existsSync(root)) {
fs.mkdirSync(root, { recursive: true })
}
2.2.4 拷貝模板文件夾:
模板拷貝的時候需要過濾掉package.json,我們會在后面單獨進行處理;
const files = fs.readdirSync(templateDir)
for (const file of files.filter((f) => f !== 'package.json')) {
write(file)
}
2.2.5 重寫 gitignore 名稱:
在上一步的模板文件夾拷貝的時候已經(jīng)用到了這個函數(shù),我們這里關系第二行中的關鍵對象 renameFiles ,實際上就是要將 _gitignore 重命名為 .gitignore ,因為在模板中直接使用 .gitignore 可能就導致關節(jié)的文件被丟失掉了;
const write = (file: string, content?: string) => {
const targetPath = path.join(root, renameFiles[file] ?? file)
if (content) {
fs.writeFileSync(targetPath, content)
} else {
copy(path.join(templateDir, file), targetPath)
}
}
2.2.6 重寫 package 字段:
最后來輸出 package.json ,需要改變里面的內(nèi)容,尤其是重要的項目名稱,命名規(guī)范也是為了符合 package 中 name 的規(guī)則;
const pkg = JSON.parse(
fs.readFileSync(path.join(templateDir, `package.json`), 'utf-8')
)
pkg.name = packageName || getProjectName()
write('package.json', JSON.stringify(pkg, null, 2))
2.2.7 后續(xù)操作提示:
在模板拷貝完畢后項目的創(chuàng)建階段也就結(jié)束了,接著就是判斷在終端執(zhí)行的包管理器來提示用戶下一步的操作了~
const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent)
const pkgManager = pkgInfo ? pkgInfo.name : 'npm'
switch (pkgManager) {
case 'yarn':
console.log(' yarn')
console.log(' yarn dev')
break
default:
console.log(` ${pkgManager} install`)
console.log(` ${pkgManager} run dev`)
break
}
3. 總結(jié)
在源碼中還支持了第三方模板通過自定義命令來創(chuàng)建項目,關鍵詞可以搜索 customCommand ,整體源碼是很簡單的,你準備好為自己創(chuàng)建一套模板管理工具了嗎~
以上就是創(chuàng)建項目及包管理yarn create vite源碼學習的詳細內(nèi)容,更多關于創(chuàng)建項目包管理yarn create vit的資料請關注腳本之家其它相關文章!
相關文章
解決vue動態(tài)為數(shù)據(jù)添加新屬性遇到的問題
今天小編就為大家分享一篇解決vue動態(tài)為數(shù)據(jù)添加新屬性遇到的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-09-09
vue如何解決數(shù)據(jù)加載時,插值表達式閃爍問題
這篇文章主要介紹了vue如何解決數(shù)據(jù)加載時,插值表達式閃爍問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01
vue引入jquery時報錯 $ is not defined的問題及解決
這篇文章主要介紹了vue引入jquery時報錯 $ is not defined的問題及解決,具有很好的參考價值,希望對大家有所幫助。2022-09-09

