核心模块开发
准备阶段

核心库:
- import-local:当前项目中的 node_modules 中存在一个脚手架命令,和全局的 node 环境中也存在一个脚手架命令的时候,它会优先选用 node_modules 中的本地版本
- commander:命令注册
工具库:
- npmlog:打印日志
- fs-extra:文件操作
- semver:版本比对
- colors:在终端打印不同的颜色文本
- user-home:快速拿到用户的主目录
- dotenv:获取环境变量
- root-check:root 账号的检查和自动降级
流程简介
const importLocal = require(‘import-local’);
// 判断 importLocal(filename) 为 true 的时候 会输出一行 log
// 判断本地 node_modules 中是否存在脚手架
// filename: 返回当前模块文件被解析过后的绝对路径
if (importLocal(__filename)) {
require(‘npmlog’).info(‘cli’, ‘正在使用 temp-cli-dev 本地版本’);
} else {
require(‘../lib’)(process.argv.slice(2)); //从进程中获取参数
}
2. 检查版本号```typescriptconst log = require('npmlog');// 加载 .json 时会使用 JSON.parse 进行转换编译从而得到一个 json 对象const pkg = require('../package.json');// 检查版本function checkPkgVersion () {log.info('cli', pkg.version);}
- 检查 node 版本
使用 semver 实现版本号的解析和比较
const semver = require('semver');const LOWEST_NODE_VERSION = '12.0.0'; // 当前可用的最低 node 版本// 检查 node 版本function checkNodeVersion () {const currentVersion = process.version; // 当前 Node 版本const lastVersion = LOWEST_NODE_VERSION;// gte(v1, v2): v1 >= v2if (!semver.gte(currentVersion, lastVersion)) {throw new Error(colors.red(`当前脚手架需要安装v${lastVersion}以上版本的Node.js`));}}
- 检查是否 root 账号
如果进行相关操作的时候使用的是 root 账号,那么会带来很多权限问题。root-check 会判断出当前系统登录账号是否是 root 账号,如果是,会自动帮我们降级,避免后续的权限问题。
// 检查登录账号的级别,是否需要降级function checkRoot () {//使用后,检查到root账户启动,会进行降级为用户账户const rootCheck = require('root-check');rootCheck();}
- 检查用户主目录是否存在
path-exists 该库的最新版不再支持 commonJS 模式
const userHome = require('user-home'); // 获取当前用户主目录const pathExists = require('path-exists').sync; //判断目录是否存在const colors = require('colors');// 检查用户主目录function checkUserHome () {if (!userHome || !pathExists(userHome)) {throw new Error(colors.red('当前登录用户主目录不存在!!!'));}}
- 检查入参
minimist 是一个轻量级的命令行参数解析引擎,利用它来解析命令行的参数,进行相应的配置
// 检查入参function checkInputArgs() {const minimist = require('minimist');let args = minimist(process.argv.slice(2));checkArgs(args);}function checkArgs(args) {if (args.debug) {process.env.LOG_LEVEL = 'verbose';} else {process.env.LOG_LEVEL = 'info';}log.level = process.env.LOG_LEVEL;}
- 检查环境变量
.env 文件中存储的数据格式是 key=value 这种格式的,获取到 .env 文件后使用 dotenv 会将里面的数据挂载到 process.env 上
const path = require('path');// 检查环境变量function checkEnv () {const dotenv = require('dotenv');const dotenvPath = path.resolve(__dirname, '../../../.env');if (pathExists(dotenvPath)) {// config will read your .env file, parse the contents, assign it to process.env,// and return an Object with a parsed key containing the loaded content or an error key if it failed.dotenv.config({path: dotenvPath});}log.info('环境变量', process.env.CLI_HOME_PORT);}function createDefaultConfig() {const cliConfig = {home: userHome}if (process.env.CLI_HOME) {cliConfig['cliHome'] = path.join(userHome, process.env.CLI_HOME);} else {cliConfig['cliHome'] = path.join(userHome, constants.DEFAULT_CLI_HOME);}process.env.CLI_HOME_PATH = cliConfig.cliHome;}
- 检查是否是最新版本,是否需要更新
```typescript
async function checkGlobalUpdate() {
//1.获取当前版本号和模块名
const currentVersion = pkg.version;
const npmName = pkg.name;
//2.调用npm API,获取所有版本号
const { getNpmSemverVersion } = require(‘@temp-cli-dev/get-npm-info’);
//3.提取所有版本号,比对哪些版本号是大于当前版本号
const lastVersion = await getNpmSemverVersion(currentVersion, npmName);
if (lastVersion && semver.gt(lastVersion, currentVersion)) {
} }//4.获取最新的版本号,提示用户更新到该版本log.warn(colors.yellow(`请手动更新${npmName},当前版本:${currentVersion},最新版本:${lastVersion}更新命令:npm install -g ${npmName}`))
const axios = require(‘axios’); const urlJoin = require(‘url-join’); const semver = require(‘semver’);
function getNpmInfo(npmName,registry) { if (!npmName) { return null; } const registryUrl = registry || getDefaultRegistry(); const npmInfoUrl = urlJoin(registryUrl,npmName); return axios.get(npmInfoUrl).then(response => { if (response.status === 200) { return response.data; } return null; }).catch(err => { return Promise.reject(err); }) }
function getDefaultRegistry(isOriginal = false) { return isOriginal ? “https://registry.npmjs.org/“ : “https://registry.npm.taobao.org/“; }
async function getNpmVersions(npmName,registry) { const data = await getNpmInfo(npmName,registry); if (data) { return Object.keys(data.versions); } else { return []; } }
function getSemverVersions(baseVersion,versions) {
return versions.filter(version =>
semver.satisfies(version,^${baseVersion})
).sort((a,b)=> semver.gt(b,a));
}
async function getNpmSemverVersion(baseVersion,npmName,registry) { const versions = await getNpmVersions(npmName, registry); const newVersions = getSemverVersions(baseVersion, versions); if (newVersions && newVersions.length > 0) { return newVersions[0]; } }
async function getNpmLatestVersion(npmName,registry) { let versions = await getNpmVersions(npmName,registry); if (versions) { return versions.sort((a,b)=> semver.gt(b,a))[0]; } return null; } ```
