国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

Vite創(chuàng )建項目的實(shí)現步驟

發(fā)布時(shí)間:2021-08-17 12:16 來(lái)源: 閱讀:0 作者:辣比老章 欄目: JavaScript 歡迎投稿:712375056

目錄

    前言

    隨著(zhù) Vite2 的發(fā)布并日趨穩定,現在越來(lái)越多的項目開(kāi)始嘗試使用它。我們使用 Vite 是一般會(huì )用下面這些命令去創(chuàng )建一個(gè)項目:

    // 使用 npm
    npm init @vitejs/app
    // 使用 yarn
    yarn create @vitejs/app
    
     
    // 想指定項目名稱(chēng)和使用某個(gè)特定框架的模版時(shí),可以像下面這樣
    // npm
    npm init @vitejs/app my-vue-app --template vue
    // yarn
    yarn create @vitejs/app my-vue-app --template vue
    
    

    運行這些命令后就會(huì )生成一個(gè)項目文件夾,對于大多數人可能覺(jué)得只要能正常創(chuàng )建一個(gè)項目就夠了,但我出于好奇,為什么運行這些命令就會(huì )生成一個(gè)項目文件夾。這里以 yarn 為例創(chuàng )建項目進(jìn)行說(shuō)明。

    yarn create 做了什么

    可能很多人會(huì )疑惑,為什么很多項目的創(chuàng )建方式都是使用yarn create這個(gè)命令進(jìn)行創(chuàng )建。除了這里的 Vite,我們創(chuàng )建 React 項目也是這樣:yarn create react-app my-app。
    那這個(gè)命令到底做了什么,它其實(shí)做了兩件事:

    yarn global add create-react-app
    create-react-app my-app

    關(guān)于yarn create的更多內容可以看這里

    源碼解析

    yarn create @vitejs/app命令運行后就會(huì )執行里的代碼。我們先看看這文件的項目結構

    template 開(kāi)頭的文件夾都是各個(gè)框架和對應的typescript版本的項目模板,我們不用太關(guān)心,創(chuàng )建項目的邏輯都在 index.js 文件里。下面就來(lái)看看這里面都做了什么

    項目依賴(lài)

    首先是依賴(lài)的引入

    const fs = require('fs')
    const path = require('path')
    const argv = require('minimist')(process.argv.slice(2))
    const prompts = require('prompts')
    const {
      yellow,
      green,
      cyan,
      blue,
      magenta,
      lightRed,
      red
    } = require('kolorist')
    

    fs、path是Nodejs內置模塊,minimist、prompts、kolorist則分別是第三方依賴(lài)庫。

    • minimist:是一個(gè)用于解析命令行參數的工具。
    • prompts:是一個(gè)命令行交互的工具。
    • kolorist:是一個(gè)使命令行輸出帶有色彩的工具。

    模版配置

    接下來(lái)不同框架模版的配置文件,最后生成一個(gè)模版名稱(chēng)的數組。

    // 這里只寫(xiě)了vue和react框架的配置,其他的都是差的不多,感興趣可以去看源碼。
    const FRAMEWORKS = [
      ......
      
      {
        name: 'vue',
        color: green,
        variants: [
          {
            name: 'vue',
            display: 'JavaScript',
            color: yellow
          },
          {
            name: 'vue-ts',
            display: 'TypeScript',
            color: blue
          }
        ]
      },
      {
        name: 'react',
        color: cyan,
        variants: [
          {
            name: 'react',
            display: 'JavaScript',
            color: yellow
          },
          {
            name: 'react-ts',
            display: 'TypeScript',
            color: blue
          }
        ]
      },
      
      ......
    ]
    
    // 輸出模版名稱(chēng)列表
    const TEMPLATES = FRAMEWORKS.map(
      (f) => (f.variants && f.variants.map((v) => v.name)) || [f.name]
    ).reduce((a, b) => a.concat(b), [])
    
    

    其次,由于 .gitignore 文件的特殊性,每種框架項目模版下都是先創(chuàng )建的 _gitignore 文件,在后續創(chuàng )建項目的時(shí)候再替換為 .gitignore。所以,代碼里會(huì )預先定義一個(gè)對象來(lái)存放需要重命名的文件:

    const renameFiles = {
      _gitignore: '.gitignore'
    }
    

    工具函數

    在開(kāi)始講的核心函數之前,先來(lái)看看代碼中定義的工具函數。最重要的是與文件操作相關(guān)的三個(gè)函數。

    copy

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

    copy函數則用于復制文件或文件夾 src 到指定文件夾 dest。它會(huì )先獲取 src 的狀態(tài) stat,如果 src 是文件夾的話(huà),即stat.isDirectory()為 true 時(shí),則會(huì )調用下面將介紹的copyDir函數來(lái)復制 src 文件夾下的文件到 dest 文件夾下。反之,src 是文件的話(huà),則直接調用 fs.copyFileSync 函數復制 src 文件到 dest 文件夾下。

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

    copyDir函數用于將某個(gè)文件夾 srcDir 中的文件復制到指定文件夾 destDir 中。它會(huì )先調用 fs.mkdirSync函數來(lái)創(chuàng )建制定的文件夾,然后調用fs.readdirSync從 srcDir 文件夾下獲取的文件并遍歷逐個(gè)復制;最后在調用copy函數進(jìn)行復制,這里用到了遞歸,因為可能存在文件夾里的文件還是文件夾。

    emptyDir

    function emptyDir(dir) {
      if (!fs.existsSync(dir)) {
        return
      }
      for (const file of fs.readdirSync(dir)) {
        const abs = path.resolve(dir, file)
        if (fs.lstatSync(abs).isDirectory()) {
          emptyDir(abs)
          fs.rmdirSync(abs)
        } else {
          fs.unlinkSync(abs)
        }
      }
    }
    

    emptyDir函數用于清空 dir 文件夾下的代碼。它會(huì )先判斷 dir 文件夾是否存在,存在則遍歷該問(wèn)文件夾下的文件,構造該文件的路徑 abs,當 abs 為文件夾時(shí),會(huì )遞歸調用 emptyDir 函數刪除該文件夾下的文件,然后再調用fs.rmdirSync刪除該文件夾;當 abs 是文件時(shí),則調用fs.unlinkSync函數來(lái)刪除該文件。

    核心函數

    接下來(lái)就是核心功能實(shí)現的init函數。

    命令行交互并創(chuàng )建文件夾

    首先是獲取命令行參數

    let targetDir = argv._[0]
    let template = argv.template || argv.t
    
    const defaultProjectName = !targetDir ? 'vite-project' : targetDir
    
    

    argv._[0] 代表 @vitejs/app 后的第一個(gè)參數
    template則是要使用的模版名稱(chēng)
    defaultProjectName則是我們創(chuàng )建的項目名稱(chēng)。
    接下來(lái)就是使用prompts包來(lái)在命令行中輸出詢(xún)問(wèn),像下面這樣:

    具體代碼如下:

    // 關(guān)于命令行交互的部分代碼沒(méi)有全部放在這里,感興趣的可以去看源碼
    let result = {}
    
    result = await prompts(
      [
        {
          type: targetDir ? null : 'text',
          name: 'projectName',
          message: 'Project name:',
          initial: defaultProjectName,
          onState: (state) =>
            (targetDir = state.value.trim() || defaultProjectName)
        },
        ......
        
      ]
    )
    
    const { framework, overwrite, packageName, variant } = result
    
    const root = path.join(cwd, targetDir)
    
    if (overwrite) {
      emptyDir(root)
    } else if (!fs.existsSync(root)) {
      fs.mkdirSync(root)
    }
    
    template = variant || framework || template
    
    // 輸出項目文件夾路徑
    console.log(`\nScaffolding project in ${root}...`)
    
    const templateDir = path.join(__dirname, `template-${template}`)
    
    

    選擇完成后會(huì )返回我們選擇的結果result
    root是通過(guò)path.join函數構建的完整文件路徑
    overwrite是針對已存在我們要創(chuàng )建的同名文件時(shí),是否要重寫(xiě),如果重寫(xiě),則調用前面的emptyDir函數清空該文件夾,如果不存在該文件夾,則調用fs.mkdirSync創(chuàng )建文件夾
    templateDir選擇的模版文件夾名稱(chēng)

    寫(xiě)入文件

    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 = require(path.join(templateDir, `package.json`))
    
    pkg.name = packageName
    
    write('package.json', JSON.stringify(pkg, null, 2))
    
    const pkgManager = /yarn/.test(process.env.npm_execpath) ? 'yarn' : 'npm'
    
    // 輸出一些提示告訴你項目已經(jīng)創(chuàng  )建結束,以及告訴你接下來(lái)啟動(dòng)項目需要運行的命令
    console.log(`\nDone. Now run:\n`)
    if (root !== cwd) {
    console.log(`  cd ${path.relative(cwd, root)}`)
    }
    console.log(`  ${pkgManager === 'yarn' ? `yarn` : `npm install`}`)
    console.log(`  ${pkgManager === 'yarn' ? `yarn dev` : `npm run dev`}`)
    console.log()
    
    

    write函數則接受兩個(gè)參數 file 和 content,它有兩個(gè)功能:

    • 對指定的文件 file 寫(xiě)入指定的內容 content,調用fs.writeFileSync函數來(lái)實(shí)現將內容寫(xiě)入文件。
    • 復制模版文件夾下的文件到指定文件夾下,調用前面介紹的copy函數來(lái)實(shí)現文件的復制。

    然后調用fs.readdirSync讀取模版文件夾里的文件,遍歷逐一復制到項目文件夾(其中要過(guò)濾的 package.json 文件,因為其中的 name 字段要修改);最后再寫(xiě)入 package.json 文件。

    小結

    Vite 的create-app包的實(shí)現只有320行左右的代碼,但它考慮到各種場(chǎng)景的兼容處理;在學(xué)習完之后,自己去實(shí)現一個(gè)這樣的CLI工具也不是什么難事。

    到此這篇關(guān)于Vite創(chuàng )建項目的實(shí)現步驟的文章就介紹到這了,更多相關(guān)Vite創(chuàng )建項目?jì)热菡埶阉髂_本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

    免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。

    www国产精品内射| 亚洲AV日韩AV永久无码PPT| 最新系列国产专区|亚洲国产| 777久久精品一区二区三区无码| 色狠狠久久AV北条麻妃| 妇女性内射冈站HDWWWCOM|