從npm init vite-app 學到的知識記錄


起初我想通過create-vite-app創建一個vite的vue項目,一開始使用全局安裝create-vite-app的方法:

npm install -g create-vite-app

全局安裝完之后,我們還需要調指令生成項目:

create-vite-app viteApp 或者 cva viteApp

然后我發現create-vite-app在npm官網中安裝方法是這樣的:

npm init vite-app <project-name>

通過這種方法安裝,我感覺跟使用npx是一樣的效果,都是避免了全局安裝,安裝完之后直接執行創建項目,也就是一步可以完成,並且不會產生全局安裝(都是臨時下載安裝,安裝完后就刪除)
用過create-react-app都知道,目前都推薦使用npx create-react-app 創建react項目,同時也可以使用npm init react-app去創建:

發現create-vite-app和create-react-app前面都有create,於是去npm包官網查看了npm init的說明:

* npm init foo -> npx create-foo
* npm init @usr/foo -> npx @usr/create-foo
* npm init @usr -> npx @usr/create

所以:npm init vite-app 和npx create-vite-app 是一樣的,npm init一個以create-開頭的和npx安裝是一樣的

我們順便拓展幾個問題點:

一、全局安裝后,為什么可以在cmd下面使用create-vite-app或cva指令?

答:我們在安裝完后,會發現全局包會被安裝到這個目錄下面:

C:\Users\J0201\AppData\Roaming\npm\node_modules\create-vite-app

同時在C:\Users\J0201\AppData\Roaming\npm下面會生成cmd文件:

node安裝后,會默認將C:\Users\J0201\AppData\Roaming\npm添加至環境變量,如果沒有添加成功,就手動修改:

(如果提示指令找不到,通常是環境變量沒設置對)

有了這個環境變量,就能在cmd下運行當前變量下面的指令,然后按照執行~

二、create-vite-app和cva是怎么生成的?

答:我們打開create-vite-app源碼(全局安裝后在C:\Users\J0201\AppData\Roaming\npm\node_modules\create-vite-app這個文件夾下面),看下package.json文件,有個bin字段:

  "bin": {
    "create-vite-app": "index.js",
    "cva": "index.js"
  },

會根據bin字段下的屬性生產對應的指令,同時執行指令會執行對應的js,也就是index.js:

同時,index.js首行需要加上,也就是如果該文件作為cmd下運行的文件,需要加上這一段在首行:

#!/usr/bin/env node

三、為何npm init vite-app 和npx create-react-app 不需要執行?

答:這個問題其實很簡單,在npm官網有說明:

[https://docs.npmjs.com/cli/v6/commands/npm-init](npm init)

initializer in this case is an npm package named create-<initializer>, which will be installed by npx,
and then have its main bin executed -- presumably creating or updating package.json
and running any other initialization-related operations.

也就是安裝完后,對應的package.json中的bin對應的腳本會被執行。

四、學習下create-vite-app中的index.js

注釋是個人理解加的,非尤大寫的(萬一哪里說的不對,不能污蔑尤大[哭笑])

#!/usr/bin/env node
const path = require('path')
const fs = require('fs-extra')
/**
 * process.argv獲取到的是一個地址數組,第3項也就是我們前面指令中創建的projectName
 * 通過minimist,argv變量存儲的是一個對象,如果沒有傳-t/-template字段,里面就只有一個屬性'_',值是對應的projectName:({ _: projectName })
 * -t/-template是通過指令中傳進來的,后面對對應的模板名,templateDir會根據值返回對應的模板,也就是cva viteApp -t vue-ts
 */
const argv = require('minimist')(process.argv.slice(2))

async function init() {
  const targetDir = argv._[0] || '.'
  const cwd = process.cwd()
  const root = path.join(cwd, targetDir)
  const renameFiles = {
    _gitignore: '.gitignore',
  }
  console.log(`Scaffolding project in ${root}...`)

  /**
   * ensureDir這個是fs創建文件夾,我們在D:根目錄下創建,對應的root就是D:/projectNam
   * 如果我們不傳projectName,根目錄下,root就是D:,fs.ensureDir(root)會返回失敗,往下便不再執行。如果不是根目錄,則existing長度不為0,表示已經存在該目錄,輸出Error: target directory is not empty,並退出程序
   * 如果傳入的projectName已存在,則existing長度不為0,表示已經存在該目錄,輸出Error: target directory is not empty,並退出程序
   */
  await fs.ensureDir(root)
  const existing = await fs.readdir(root)
  if (existing.length) {
    console.error(`Error: target directory is not empty.`)
    process.exit(1)
  }

  /**
   * 往下執行完便成功,會生成模板,並輸出相應的console.log
   */

  const templateDir = path.join(
    __dirname,
    `template-${argv.t || argv.template || 'vue'}`
  )
  const write = async (file, content) => {
    const targetPath = renameFiles[file]
      ? path.join(root, renameFiles[file])
      : path.join(root, file)
    if (content) {
      await fs.writeFile(targetPath, content)
    } else {
      await fs.copy(path.join(templateDir, file), targetPath)
    }
  }

  const files = await fs.readdir(templateDir)
  for (const file of files.filter((f) => f !== 'package.json')) {
    await write(file)
  }

  const pkg = require(path.join(templateDir, `package.json`))
  pkg.name = path.basename(root)
  await write('package.json', JSON.stringify(pkg, null, 2))

  console.log(`\nDone. Now run:\n`)
  if (root !== cwd) {
    console.log(`  cd ${path.relative(cwd, root)}`)
  }
  console.log(`  npm install (or \`yarn\`)`)
  console.log(`  npm run dev (or \`yarn dev\`)`)
  console.log()
}

init().catch((e) => {
  console.error(e)
})

五、我們會了這個,對我們有什么用,如何學以致用?

答:最近想做一個模板生成器,也就是使用命令生成vue的頁面模板,生成后簡單修改下配置,便是我們的完整頁面,這樣在團隊協助中,能夠加快開發速度。我覺得可以使用bin腳本去執行,通過生成cmd指令,執行指令后,結合模板生成器的代碼,輸出相應的頁面。
如果公司有條件搭建了屬於公司自己的私庫,我們可以學習create-vite-app的做法,創建以create-開頭的包,並上傳到私庫,然后全局安裝也好,npm init/npx也好,就可以像create-vite-app一樣,直接調用bin中的指令執行。
如果沒有私庫,代碼不擔心公開問題可以放npm官網。不行的話可以在當前包下面使用npm link,生成全局命令。npm link后,會把當前的包安裝到全局\AppData\Roaming\npm下,同時也會生成bin中的指令,在\AppData\Roaming\npm當前包是以快捷方式的形式直接訪問的,所以修改的時候,全局也會跟着修改。比較適合開發的時候。

這一步,我后面會做個簡單的demo后會再記錄一下。

六、拓展什么是npx和vite

npx推薦阮一峰的[http://www.ruanyifeng.com/blog/2019/02/npx.html](npm 使用教程)

最重要兩點:

  1. 調用項目安裝的模塊
  2. 避免全局安裝模塊

什么是vite:

作者原話: Vite,一個基於瀏覽器原生 ES Modules 的開發服務器。利用瀏覽器去解析模塊,在服務器端按需編譯返回,完全跳過了打包這個概念,服務器隨起隨用。同時不僅有 Vue 文件支持,還搞定了熱更新,而且熱更新的速度不會隨着模塊增多而變慢。

Vite(讀音類似於[weɪt],法語,快的意思) 是一個由原生 ES Module 驅動的 Web 開發構建工具。在開發環境下基於瀏覽器原生 ES imports 開發,在生產環境下基於 Rollup 打包。

Vite的特點:

  • Lightning fast cold server start - 閃電般的冷啟動速度
  • Instant hot module replacement (HMR) - 即時熱模塊更換(熱更新)
  • True on-demand compilation - 真正的按需編譯

為了實現上述特點,Vite 要求項目完全由 ES Module 模塊組成,common.js 模塊不能直接在 Vite 上使用。因此不能直接在生產環境使用。在打包上依舊還是使用 rollup 等傳統打包工具。因此 Vite 目前更像是一個類似於 webpack-dev-server 的開發工具.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM