起初我想通过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 的开发工具.