Create?vite理解Vite項目創(chuàng)建流程及代碼實現(xiàn)
前言
繼上次閱讀create-vue后 ,本次接著來解析 create-vite
, 得益于之前的閱讀經(jīng)驗, 本篇筆記將會著重講解代碼執(zhí)行流程以及函數(shù)的擴展
最新的 create-vite
已經(jīng)升級為Ts編譯了,為方便學習理解使用川哥提供的源碼倉庫
git clone github.com/lxchuan12/v…
monorepo
Vite
和Vue
都使用monorepo的形式管理代碼,將原本多代碼倉庫變?yōu)閱未a倉庫,每一個包對應的就是一個項目,這些項目都具有相關性,但在邏輯上是獨立的。
主流程
入口文件
vite2/packages/create-vite/index.js
主要結構
import fs from 'node:fs' import path from 'node:path' //... async function init() { //... try { result = await prompts( [ //省略若干選項代碼 ], { onCancel: () => { throw new Error(red('?') + ' Operation cancelled') } } ) } catch (cancelled) { console.log(cancelled.message) return } //若干處理代碼 } init().catch((e) => { console.error(e) })
index.js
核心就是執(zhí)行 init
這個異步函數(shù), 通過選項式對話 取到配置變量后 執(zhí)行操作
擴展插件
import minimist from 'minimist' import prompts from 'prompts' import { blue, cyan, green, lightRed, magenta, red, reset, yellow } from 'kolorist'
minimist
用于獲取命令行參數(shù),用于跳過后續(xù)一些選項式對話
prompts
提供了選項式對話的 命令行工具
kolorist
用來在命令行輸出不同顏色的字符
模板配置
const FRAMEWORKS = [ { name: 'vanilla', color: yellow, variants: [ { name: 'vanilla', display: 'JavaScript', color: yellow }, { name: 'vanilla-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), [])
TEMPLATES
主要用來根據(jù)定義好的配置對象 生成對應后續(xù)template
用到的數(shù)組
getProjectName
const getProjectName = () => //path.resolve() 默認返回當前目錄 //path.basename(path.resolve()) 對應得到的就是 當前目錄名 targetDir === '.' ? path.basename(path.resolve()) : targetDir
用于獲取項目名, 值得一提的是 path.resolve()
默認返回命令執(zhí)行的目錄,path.basename(path.resolve())
就是獲取當前目錄名
formatTargetDir
function formatTargetDir(targetDir) { return targetDir?.trim().replace(/\/+$/g, '') }
將文本去空,并將末尾的 /
斜杠去掉
npm包名驗證和轉化
function toValidPackageName(projectName) { return projectName .trim() .toLowerCase() .replace(/\s+/g, '-') .replace(/^[._]/, '') .replace(/[^a-z0-9-~]+/g, '-') } function isValidPackageName(projectName) { return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test( projectName ) }
用于驗證是否符合package.json
name 的格式 以及轉換函數(shù)
取得模板目錄
const templateDir = path.resolve( fileURLToPath(import.meta.url), '..', `template-${template}` )
通過resolve
拼接目錄名,根據(jù)用戶的選擇會生成對應的 比如 template-vue-ts
得到npm包管理器相關信息
const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent) const pkgManager = pkgInfo ? pkgInfo.name : 'npm' function pkgFromUserAgent(userAgent) { if (!userAgent) return undefined const pkgSpec = userAgent.split(' ')[0] const pkgSpecArr = pkgSpec.split('/') return { name: pkgSpecArr[0], version: pkgSpecArr[1] } }
process.env.npm_config_user_agent
會返回類似這樣的字符:
npm/6.7.5 xxxx/xxx xxx ,函數(shù)就是取出第一部分然后切割字符, 得到對應的 包管理器以及版本
文件操作相關的函數(shù)
write函數(shù) 寫入文件
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) } }
targetPath
先匹配.gitignore
,否則直接使用參數(shù)的file值。 然后根據(jù)是否傳遞了 content
參數(shù)執(zhí)行寫入 和 復制 template目錄下文件 兩個操作
copy函數(shù) 復制文件
function copy(src, dest) { const stat = fs.statSync(src) if (stat.isDirectory()) { copyDir(src, dest) } else { fs.copyFileSync(src, dest) } }
判斷文件信息, 目錄則執(zhí)行 copyDir函數(shù), 否則調(diào)用 fs 下 的 copyFileSync
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) } }
創(chuàng)建目標文件夾,然后遍歷源文件夾 依次將文件 copy過去
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 }) } }
將目錄變?yōu)榭漳夸洝O扰袛嗄夸浭欠翊嬖冢?再遍歷執(zhí)行刪除操作
isEmpty 判斷目錄為空
function isEmpty(path) { const files = fs.readdirSync(path) return files.length === 0 || (files.length === 1 && files[0] === '.git') }
通過fs.readdirSync
得到目錄返回的數(shù)組長度 進行判斷
核心代碼
const { framework, overwrite, packageName, variant } = result 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 console.log(`\nScaffolding project in ${root}...`) //得到模板目錄 const templateDir = path.resolve( fileURLToPath(import.meta.url), '..', `template-${template}` ) const write = (file, content) => { //寫文件函數(shù) } const files = fs.readdirSync(templateDir) //得到模板目錄下文件信息 //將默認目錄中非package.json 的文件 復制到 templateDir中 for (const file of files.filter((f) => f !== 'package.json')) { write(file) //不傳 content 執(zhí)行 copy操作 } //得到模板目錄中的 package.json內(nèi)容 const pkg = JSON.parse( fs.readFileSync(path.join(templateDir, `package.json`), 'utf-8') ) pkg.name = packageName || getProjectName() // 修改name 后 寫入 package.json 到 templateDir中中 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 } console.log()
這一步總體流程如下:
- 檢查目錄是否可寫入
- 得到對應的模板目錄
- 寫入模板目錄的文件到 用戶的目錄中
- 取得包管理器信息 回返顯示 提示信息
總結
path.resolve
是相對于當前工作目錄 返回路徑
path.join
是 根據(jù)path字符串片段拼接返回一個路徑 需要注意區(qū)別
至此 代碼和流程就分析完畢了,相對于create-vue
, create-vite
要簡單一點點
對于不懂或者不了解的地方, 復現(xiàn)或者嘗試重寫進行舉一反三 是加深 認知 和學習 更好的方式,光是看和閱讀領悟還是不夠的!
寫了個練習用的小工具,可以用來快捷的生成Vue
模板頁面
以上就是Create vite理解Vite項目創(chuàng)建流程及代碼實現(xiàn)的詳細內(nèi)容,更多關于Create vite 項目創(chuàng)建流程的資料請關注腳本之家其它相關文章!
相關文章
使用vue+element?ui實現(xiàn)走馬燈切換預覽表格數(shù)據(jù)
這次做項目的時候遇到需要切換預覽表格數(shù)據(jù)的需求,所以下面這篇文章主要給大家介紹了關于使用vue+element?ui實現(xiàn)走馬燈切換預覽表格數(shù)據(jù)的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-08-08Vue3+Element Plus實現(xiàn)自定義彈窗組件的全屏功能
在現(xiàn)代化的前端開發(fā)中,彈窗組件是提升用戶體驗的重要元素,本文將介紹如何使用 Vue 3 和 Element Plus 庫來創(chuàng)建一個具有全屏功能的自定義彈窗組件,文中通過代碼示例講解的非常詳細,需要的朋友可以參考下2024-07-07詳解windows下vue-cli及webpack 構建網(wǎng)站(四) 路由vue-router的使用
本篇文章主要介紹了windows下vue-cli及webpack 構建網(wǎng)站(四) 路由vue-router的使用,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06