從npm init vite-app <project-name>學到的知識記錄
起初我想通過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
發現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
我們順便拓展幾個問題點:
一、全域性安裝後,為什麼可以在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
答:這個問題其實很簡單,在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 使用教程)
最重要兩點:
- 呼叫專案安裝的模組
- 避免全域性安裝模組
什麼是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 的開發工具.