起初我想通過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 的開發工具.