vue-cli脚手架源码解析(一)
前言:前段时间撸过react脚手架,现在新公司用vue,最近花时间撸一下vue-cli,撸完之后,再亲自写一个简化版的cli。
看脚手架的思路,就是顺着package.json文件看下去即可,看bin字段到底执行的是什么文件。
正式开始
react,vue脚手架都用的lerna分包,所以一进来直接去看packages目录,进入@vue目录,最后来到cli目录下。
1. 按照惯例,这种脚手架都可以分为两部分
- 生成项目基本文件,组织文件结构,说白了就是创建样板项目,如 vue create hello-word
- 开发命令如 vue-cli-service serve | build | lint。
vue create hello-word
就从这个命令出发,看看这个命令到底做了哪些操作。
可以看到vue其实是执行了bin 目录下的vue.js文件。
2. vue.js,了解依赖的库和文件
这个文件我讲细致一点点,直接从上而下过代码。
const chalk = require('chalk') // 相等于console的时候加上了颜色, const semver = require('semver') // 规范版本号 const requiredVersion = require('../package.json').engines.node // 获取依赖的node最低版本 const didYouMean = require('didyoumean') // 有点类似于纠正输出错误,用户输出错误命令,给出联想提示。
checkNodeVersion(requiredVersion, 'vue-cli') // 这个方法,判定当前node版本是否低于最低要求版本requiredVersion
const fs = require('fs') //文件模块 const path = require('path') //路径模块 const slash = require('slash') // 用于转换 Windows 反斜杠路径转换为正斜杠路径 \ => / const minimist = require('minimist') // 解析命令行参数 process.argv,有的项目用arg。
const program = require('commander') //这个就是命令库,定义命令,说白点,就是定义一个create命令,当你输入vue create的时候就会执行对应的方法。 const loadCommand = require('../lib/util/loadCommand') // 这个是自定义方法,根据不同的参数加载不同的js文件,比如test就加载test.js,里面有异常流处理,比如文件不存在怎么办,这里就不多复述。
3. create命令
他这里定义非常非常多的命令,但是我们一般就用一个create,这里只详细讲解这一个。
前置知识点,commander库,这个库是用来定义命令的,有一些基本知识点,可以先去了解一下。
program .command('create <app-name>') .description('create a new project powered by vue-cli-service') .option('-p, --preset <presetName>', 'Skip prompts and use saved or remote preset') .option('-d, --default', 'Skip prompts and use default preset') .option('-i, --inlinePreset <json>', 'Skip prompts and use inline JSON string as preset') .option('-m, --packageManager <command>', 'Use specified npm client when installing dependencies') .option('-r, --registry <url>', 'Use specified npm registry when installing dependencies (only for npm)') .option('-g, --git [message]', 'Force git initialization with initial commit message') .option('-n, --no-git', 'Skip git initialization') .option('-f, --force', 'Overwrite target directory if it exists') .option('-c, --clone', 'Use git clone when fetching remote preset') .option('-x, --proxy', 'Use specified proxy when creating project') .option('-b, --bare', 'Scaffold project without beginner instructions') .option('--skipGetStarted', 'Skip displaying "Get started" instructions') .action((name, cmd) => { const options = cleanArgs(cmd) // 对options参数做一些格式化 if (minimist(process.argv.slice(3))._.length > 1) { // 输入的参数太多,不合法,走默认值 } // --git makes commander to default git to true if (process.argv.includes('-g') || process.argv.includes('--git')) { options.forceGit = true } require('../lib/create')(name, options) })
看源码说话,create 代表命令 <app-name>表示项目名,后面带-表示参数,一个完整的命令就是 create hello -p 。一旦process.argvs中带了 create 就会执行这个命令,并且进入到action中去,执行对应的操作。
require('../lib/create')(name, options) 到这里算是走完了最简单的一步,解析出参数,然后执行真正的create文件,并将参数传过去。 至于create文件里面的故事,下一章再讲。