欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 前端技术 > vue >内容正文

vue

vue 使用fs_模仿vue-cli,手写一个脚手架

发布时间:2025/3/19 vue 41 豆豆
生活随笔 收集整理的这篇文章主要介绍了 vue 使用fs_模仿vue-cli,手写一个脚手架 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

vue-cli

在vue的开发的过程中,经常会使用到vue-cli脚手架工具去生成一个项目。在终端运行命令vue create hello-world后,就会有许多自动的脚本运行。

  • 为什么会这样运行呢?
  • 我们自己是否也能写一个脚手架工具?
    带着这样的疑问,我们先来看看vue-cli。

解读vue-cli

首先我们可以来到vue-cli的安装目录:
mac用户来到路径:/usr/local/lib/node_modules 可以看到(windows可以自行到全局安装的目录下查看)

此时用我们的编辑器 打开@vue文件:

lib内放的是具体各种配置和各种类,对于我们来说,这个目录内的就是所谓的业务逻辑。
bin内放的就是脚本命令的入口,调用lib的入口,入口在package.json内红框定义。我们姑且先放下业务逻辑,来看看这个入口文件。

现在,我们先放下所有的疑虑,我们打开bin/vue.js。我们可以看到以下内容:

看完之后有什么感觉?咦?怎么跟终端内输出的好像?没错,就是这样,这就是我们使用vue-cli的时候具体的命令。我们去终端输入vue:

发现了吗,终端内的具体命令全在vue.js内定义过了。

program.command('create <app-name>').description('create a new project powered by vue-cli-service') program.command('add <plugin> [pluginOptions]').description('install a plugin and invoke its generator in an already created project') program.command('invoke <plugin> [pluginOptions]')

好了,剩下代码有兴趣的可以自行打开对应目录读下去,可以学习人家优秀的设计思想。对于本文来说,剩下的许多东西都是业务代码了。我们开头的疑问为什么会这样运行呢?已经了解了一个大概了。我们现在来看看我们自己是否也能写一个脚手架工具?,答案是肯定的。开始动手吧。

手写一个自己的脚手架

先来看看可能需要用到哪些npm的包:

  • commander:参数解析
  • inquirer:交互式命令行工具,有他就可以实现命令行的选择功能
  • chalk:输出文本颜色,为了美丽~
    后续可能随着模块的增加,会出现更多需要的包

1. 创建项目

npm init -y # 初始化package.json

2. 创建文件目录

  • 在package.json内添加“bin”
  • bin下的文件没有格式,且第一行必须是#! /usr/bin/env node

3. 链接包到全局

npm link # // 取消链接 npm unlink

有时候可能需要在上面命令后面拼接 --force,mac权限问题记得前面sudo
可以去目录:/usr/local/lib/node_modules 查看,发现我们多了一个,同时在这时候终端输入一下试试,我们在package.json下叫的name叫superman-cli,所以我们的命令就是叫superman-cli:

好了,基础配置初始化的工作全部结束了!

4. 第一个命令

首先安装包commander

npm install commander --save

在目录bin/superman内

#! /usr/bin/env node// console.log(1) const program = require('commander')program.version(`Version is ${require('../package.json').version}`).description('从0开始 手写脚手架').usage('<command> [options]')program.parse(process.argv)

测试有效!

然后我们在前面Version命令下加入代码:

program.command('create <app-name>').description('create a new project').option('-f, --force', 'Overwrite target directory if it exists').option('-c, --clone', 'Use git clone when fetching remote preset').action((name, cmd) => {console.log('name', name)console.log('cmd', cmd)})

仔细对比我们的代码合终端的输出,我们就可以看到我们写的很多东西都生效了。接下来我们就优化一下.action下的参数,毕竟一大堆也不好处理:

program.command('create <app-name>').description('create a new project').option('-f, --force', 'Overwrite target directory if it exists').option('-c, --clone', 'Use git clone when fetching remote preset').action((name, cmd) => {const options = cleanArgs(cmd)console.log(options)}) function camelize (str) {return str.replace(/-(w)/g, (_, c) => c ? c.toUpperCase() : '') } function cleanArgs (cmd) {const args = {}// console.log(cmd)cmd.options.forEach(o => {const key = camelize(o.long.replace(/^--/, ''))// console.log(key)// console.log(cmd[key])// console.log(typeof cmd[key])if (typeof cmd[key] !== 'function' && typeof cmd[key] !== 'undefined') {args[key] = cmd[key]}})return args }

具体不懂的也可以像我注释的console.log一样,慢慢看就明白了


image

我们第一个命令已经完成一大半了,接下来就是我们这个create命令具体干什么事情。(在这个文件里,我们只管命令,就像vue-cli一样,这也是我们需要学习的地方,模块如何去处理)

// 在上面.action内补充一行代码.action((name, cmd) => {const options = cleanArgs(cmd)console.log(options)require('../lib/create')(name, options)})

同时去lib下创建文件create.js

const path = require('path') // const fs = require('fs-extra') async function create (projectName, options) {console.log(projectName, options)const cwd = process.cwd(); // 获取当前命令执行时的工作目录const targetDir = path.join(cwd,projectName); // 目标目录console.log(targetDir) }module.exports = (...args) => {return create(...args) }

继续执行superman-cli create hello -f,我们可以得到,force:true,如果新建的话,将来的目录会是/Users/chenjing/hello

接下来我们尝试创建目录hello,不过我们需要考虑几个问题:

  • 是否已经存在目录hello了?(使用fs-extra包)
  • 若存在是要删除覆盖还是停止操作?(这里就需要用到插件inquirer啦,进行选择)
npm install fs-extra --save npm install inquirer --save

直接上代码:

const path = require('path') const fsextra = require('fs-extra') const fs = require('fs') const Inquirer = require('inquirer') async function create (projectName, options) {console.log(projectName, options)const cwd = process.cwd(); // 获取当前命令执行时的工作目录const targetDir = path.join(cwd,projectName); // 目标目录console.log(targetDir)if (fsextra.existsSync(targetDir)) {if (options.force) {// 如果强制创建 ,删除已有的await fsextra.remove(targetDir);console.log('删除成功')createDir(projectName)} else {let { action } = await Inquirer.prompt([{name: 'action',type: 'list',message: 'Target directory already exists Pick an action:',choices: [{name:'Overwrite',value:'overwrite'},{name:'Cancel',value:false}]}])if (!action) {console.log('取消操作')return} else if (action === 'overwrite') {console.log(`rnRemoving....`);await fsextra.remove(targetDir)console.log('删除成功')createDir(projectName)}}} else {createDir(projectName)} } function createDir (projectName) {fs.mkdir(`./${projectName}`, function (err) {if (err) {console.log('创建失败')} else {console.log('创建成功')}}) }module.exports = (...args) => {return create(...args) }

看效果,先来的一个空目录

superman-cli create hello superman-cli create hello // 再次 superman-cli create hello -f // 覆盖

4. 小结

本篇的源码github地址

并不是说我们手写脚手架就到此结束了,只是要完整实现一个功能不是一两篇文章可以搞定的。不过我相信写到这里,动手能力强的一定也能体验一把手动模仿vue-cli的爽了。至于能写出什么牛C的脚手架,真的就是个人需求和业务代码堆加。当然可以发散思维后续还可以做许多许多事情。强烈建议阅读vue-cli。或者其他脚手架的源码,都在目录:/usr/local/lib/node_modules 下面,看源码真的是学习最直接的方法了,甚至copy人家的代码到自己的cli内执行。其乐无穷

作者:超人陈立青
链接:https://www.jianshu.com/p/75de24392de8
来源:简书

总结

以上是生活随笔为你收集整理的vue 使用fs_模仿vue-cli,手写一个脚手架的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。