从0开发一个高性能前端脚手架-第六篇-脚手架准备阶段实现(3)

221 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情

上篇文章讲解了检查node版本和检查root启动,接着下面按照这个图来实现准备阶段

image.png

检查用户主目录

检查用户主目录实现

const userHome = require('user-home')
const pathExists = require('path-exists').sync;

// 检查用户主目录
function checkUserHome(){
    if(!userHome || !pathExists(userHome)){
        throw new Error(colors.red('当前登录用户主目录不存在'))
    }
}

其中使用到了两个第三方node库,分别是user-home和path-exists。

下面看下这两个node库

user-home

功能

可以跨操作系统获取用户主目录

源码

// user-home
'use strict';
module.exports = require('os-homedir')();


// os-homedir
'use strict';
var os = require('os');

function homedir() {
	var env = process.env;
	var home = env.HOME;
	var user = env.LOGNAME || env.USER || env.LNAME || env.USERNAME;

	if (process.platform === 'win32') {
		return env.USERPROFILE || env.HOMEDRIVE + env.HOMEPATH || home || null;
	}

	if (process.platform === 'darwin') {
		return home || (user ? '/Users/' + user : null);
	}

	if (process.platform === 'linux') {
		return home || (process.getuid() === 0 ? '/root' : (user ? '/home/' + user : null));
	}

	return home || null;
}

module.exports = typeof os.homedir === 'function' ? os.homedir : homedir;

path-exists

功能

判断文件路径是否存在

源码

'use strict';
const fs = require('fs');
const {promisify} = require('util');

const pAccess = promisify(fs.access);

module.exports = async path => {
	try {
		await pAccess(path);
		return true;
	} catch (_) {
		return false;
	}
};

module.exports.sync = path => {
	try {
		fs.accessSync(path);
		return true;
	} catch (_) {
		return false;
	}
};

检查入参和debug模式

可能会使用debug模式,需要提前检查入参

实现

// 检查入惨
function checkInputArgs(){
    const minimst = require('minimist')
    args = minimst(process.argv.slice(2))
    checArgs()
}
// 检查参数
function checArgs(){
    if(args.debug){
        process.env.LOG_LEVEL = 'verbose'
    }else{
        process.env.LOG_LEVEL = 'info'
    }
    log.level = process.env.LOG_LEVEL; // 后置修改log level
}

其中使用了minimist第三方node库

通过minimist来进行参数解析,当用户命令中有debug,则进入debug模式,否则是普通模式

minimist

进行参数解析

效果

可以进入debug模式

检查环境变量

将一些变量,如账号存到环境变量中,不写到代码里,可以实时读取

实现

// 检查环境变量
function checkEnv(){
    const dotenv = require('dotenv');
    const dotenvPath = path.resolve(userHome,'.env');
    if(pathExists(dotenvPath)){
        config = dotenv.config({
            path: dotenvPath
        });
    }
   
    log.verbose('环境变量', config)
}

其中使用dotenv第三方node库,具体可以看下npm

dotenv

从.env中加载环境变量

效果

image.png

加上默认环境变量

// 检查环境变量
function checkEnv(){
    const dotenv = require('dotenv');
    const dotenvPath = path.resolve(userHome,'.env');
    if(pathExists(dotenvPath)){
        dotenv.config({
            path: dotenvPath
        });
    }
    createDefaultConfig()
    // 获取cliHomePathq				
    log.verbose('环境变量', process.env.CLI_HOME_PATH)
}
// 如果没有环境变量。默认配置
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,DEFAULT_CLI_HOME)
    }
    // 将cliHome放入环境变量中,随时可以取
    process.env.CLI_HOME_PATH = cliConfig.cliHome
}

效果

image.png

检查当前是否为最新版本

1.获取当前版本号和模块名

2.调用npm API,获取所有版本号

3.提取所有版本号,比对哪些版本号是大于当前版本号

4.获取最新版本号,提示用户更新到该版本

实现

// 检查是否要全局更新
async function checkGlobalUpdate(){
    // 1.获取当前版本号和模块名
    const currentVersion = pkg.version;
    const npmName = pkg.name;
    // 2.调用npm API,获取所有版本号
    const {getNpmSemverVersion } = require('@rd-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}
        `))
    }
   
}

get-npm-info模块

'use strict';

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);
    console.log(npmInfoUrl)
    return axios.get(npmInfoUrl).then(res => {
        if(res.status === 200){
            return res.data;
        }else{
            return null;
        }
    }).catch(err => {
        return Promise.reject(err)
    })
}   
// 获取默认的registry
function getDefaultRegistry(isOriginal = true){
    return isOriginal ? 'https://registry.npmjs.org': 'https://registry.npmj.taobao.org'
}

// 获取 npm versions
async function getNpmVersions(npmName, registry){
    const data = await getNpmInfo(npmName, registry)
    if(data){
       return Object.keys(data.versions)
    }else{
        return [];
    }
}
// 获取所有满足条件的版本号
function getNpmSemverVersions(baseVersion, versions){
    return versions.filter(version => 
      semver.satisfies(version, `^${baseVersion}`)    
    ).sort((a,b)=>{
        return semver.gt(b,a)
    })
}
// 获取最新版本
async function getNpmSemverVersion(baseVersion, npmName,registry){
    const versions = await getNpmVersions(npmName, registry)
    const newVersions = getNpmSemverVersions(baseVersion, versions)
    console.log('newVersions', newVersions)
    if(newVersions && newVersions.length > 0){
        return newVersions[0]
    }
}
module.exports = {
    getNpmInfo,
    getNpmVersions,
    getNpmSemverVersion
};