目录
脚手架框架代码拆包 + import-local应用
检查版本号功能开发(require加载资源类型讲解 + npmlog封装)
最低Node版本检查功能开发
root 账号启动检查和自动降级功能开发
用户主目录检查功能开发
入参检查和 debug 模式开发
环境变量检查功能开发
通用 npm API 模块封装
npm 全局更新功能开发
脚手架框架代码拆包 + import-local应用
core > cli > bin > index.js中
#! /usr/bin/env node
const importLocal = require('import-local');
if (importLocal(__filename)) {
require('npmlog').info('cli', '正在使用 imooc-cli 本地版本');
} else {
require('../lib')(process.argv.slice(2));
}
检查版本号功能开发(require加载资源类型讲解 + npmlog封装)
require加载资源类型讲解:
支持三种类型:.js / .json / .node
.js -> module.exports / exports
.json -> JSON.parse()
.node -> 是一个c++的插件,通过 process.dlopen 打开
any -> 通过 js 引擎解析
可以定义一个专门的 log 类,在 utils 中定义一个 log package:
lerna create @imooc-cli-dev/log
调整 .log 目录位置,修改 log/lib/log.js 名字为 index.js(package.json中对应修改)。
lerna add npmlog utils/log/
在 core/cli 模块中调用 log package,在 core/cli/package.json 中注册:
"dependencies": {
"@imooc-cli-dev/log": "file:../../utils/log",
"@imooc-cli-dev/init": "file:../../commands/init",
"import-local": "^3.0.2",
"npmlog": "^4.1.2"
},
cd core/cli/
npm link
// log/lib/index.js 中
'use strict';
const log = require('npmlog');
log.level = process.env.LOG_LEVEL ? process.env.LOG_LEVEL : 'info'; // 判断debug模式
log.heading = 'imooc'; // 修改前缀
log.addLevel('success', 2000, { fg: 'green', bold: true }); // 添加自定义命令
module.exports = log;
最低Node版本检查功能开发
使用的 node api,在低版本的时候是不支持的。要设置一个最低的版本号。
semver库作用:
用来做各种各样版本号比对的。
//用法
const semver = require('semver')
semver.valid('1.2.3') // '1.2.3'
semver.valid('a.b.c') // null
semver.clean(' =v1.2.3 ') // '1.2.3'
semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') // true
semver.gt('1.2.3', '9.8.7') // false
semver.lt('1.2.3', '9.8.7') // true
semver.minVersion('>=1.0.0') // '1.0.0'
semver.valid(semver.coerce('v2')) // '2.0.0'
semver.valid(semver.coerce('42.6.7.9.3-alpha')) // '42.6.7'
colors库作用:
Get colors in your node.js console
var colors = require('colors/safe');
console.log(colors.green('hello')); // outputs green text
console.log(colors.red.underline('i like cake and pies')) // outputs red underlined text
console.log(colors.inverse('inverse the color')); // inverses the color
console.log(colors.rainbow('OMG Rainbows!')); // rainbow
console.log(colors.trap('Run the trap')); // Drops the bass
引入和实现代码:
lerna add semver core/cli/
lerna add colors core/cli/
function checkNodeVersion() {
const currentVersion = process.version;
const lowestVersion = constant.LOWEST_NODE_VERSION;
if (!semver.gte(currentVersion, lowestVersion)) {
throw new Error(colors.red(`imooc-cli 需要安装 v${lowestVersion} 以上版本的 Node.js`))
}
}
root 账号启动检查和自动降级功能开发
需要对操作系统比较了解,才能理解。脚手架需要频繁读写文件,root 账号会导致权限频繁报错,需要进行降级处理。
判断 root 环境:
process.getuid && process.getuid() == 0
process.setuid()
process.setgid() //分组id
process.env //环境变量
process //node进程信息
root-check 库作用:
Try to downgrade the permissions of a process with root privileges and block access if it fails
//用法
import rootCheck from 'root-check';
rootCheck();
引入和实现代码:
lerna add root-check core/cli/
在 core/cli/ 命令行中 npm link
function checkRoot() {
const rootCheck = require('root-check');
rootCheck();
}
用户主目录检查功能开发
user-home库作用:
跨操作系统获取系统主目录。已弃用。
Deprecated. Just use import {homedir} from 'os';
//用法
const userHome = require('user-home');
console.log(userHome);
//=> '/Users/sindresorhus'
path-exists库作用:
判断文件是否存在。
原理:fs.accessSync(path);
//用法
// foo.js
import {pathExists} from 'path-exists';
console.log(await pathExists('foo.js'));
//=> true
引入和实现代码:
lerna add user-home core/cli/
lerna add path-exists core/cli/
在 core/cli/ 命令行中 npm link
function checkUserHome() {
if (!userHome || !pathExists(userHome)) {
throw new Error(colors.red('当前登录用户主目录不存在!'));
}
}
入参检查和 debug 模式开发
入参检查目的:看一下是否进入调试模式。
minimist库作用:
parse argument options
//用法
var argv = require('minimist')(process.argv.slice(2));
console.log(argv);
$ node example/parse.js -a beep -b boop
{ _: [], a: 'beep', b: 'boop' }
$ node example/parse.js -x 3 -y 4 -n5 -abc --beep=boop foo bar baz
{
_: ['foo', 'bar', 'baz'],
x: 3,
y: 4,
n: 5,
a: true,
b: true,
c: true,
beep: 'boop'
}
引入和实现代码:
core/cli/ 命令行中执行 npm install -S minimist
function checkInputArgs() {
const minimist = require('minimist')
args = minimist(process.argv.slice(2))
checkArgs()
}
function checkArgs() {
if (args.debug) {
process.env.LOG_LEVEL = 'verbose'
} else {
process.env.LOG_LEVEL = 'info'
}
log.level = process.env.LOG_LEVEL
}
环境变量检查功能开发
重要意义:可以在操作系统当中配置一些环境变量,将用户名密码等敏感信息保存在用户本地。而不用集成到代码当中,我们需要时就可以实时进行读取。同时我们还可以修改默认的配置信息。
通过环境变量在全局进行获取,操作系统打开以后,不管哪个软件之中都可以获取的到。共享一份。
dotenv库作用:
Dotenv is a zero-dependency module that loads environment variables from a .env
file into process.env. Storing configuration in the environment separate from code is based on The Twelve-Factor App methodology.
//用法
//Create a .env file in the root of your project:
S3_BUCKET="YOURS3BUCKET"
SECRET_KEY="YOURSECRETKEYGOESHERE"
//As early as possible in your application, import and configure dotenv:
require('dotenv').config()
console.log(process.env) // remove this after you've confirmed it is working
引入和实现代码:
core/cli/ 命令行中执行 npm install -S dotenv
const userHome = require('user-home');
function checkEnv() {
const dotenv = require('dotenv');
const dotenvPath = path.resolve(userHome, '.env');
if (pathExists(dotenvPath)) {
dotenv.config({
path: dotenvPath,
});
}
createDefaultConfig();
}
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, constant.DEFAULT_CLI_HOME);
}
process.env.CLI_HOME_PATH = cliConfig.cliHome;
}
//最终缓存路径 /Users/sam/.imooc-cli
通用 npm API 模块封装
url-join库作用:
Join all arguments together and normalize the resulting URL.
//用法
import urlJoin from 'url-join';
const fullUrl = urlJoin('http://www.google.com', 'a', '/b/cd', '?foo=123');
console.log(fullUrl);
//Prints:
//'http://www.google.com/a/b/cd?foo=123'
步骤:
1. 获取当前版本号和模块名
2. 调用 npm API(https://registry.npmjs.org/模块名称、https://registry.npm.taobao.org/模块名称 ),获取所有版本号
3. 提取所有版本号,比对哪些版本号是大于当前版本号
4. 获取最新的版本号,提示用户更新到该版本
操作:
lerna create get-npm-info ./utils/get-npm-info
看实际情况调整 get-npm-info package 位置,lib/get-npm-info.js 改为 lib/index.js,package.json 中 main 属性相应修改。
//core/cli 的 package.json 中注册
"dependencies": {
"@imooc-cli-dev/get-npm-info": "file:../../utils/get-npm-info",
"colors": "^1.4.0"
}
//core/cli 命令行中执行 npm link
lerna add axios utils/get-npm-info/
lerna add semver utils/get-npm-info/
lerna add url-join utils/get-npm-info/
// utils/get-npm-info/命令行中
npm link
npm 全局更新功能开发
async function checkGlobalUpdate() {
const currentVersion = pkg.version;
const npmName = pkg.name;
const { getNpmSemverVersion } = require('@imooc-cli-dev/get-npm-info');
const lastVersion = await getNpmSemverVersion(currentVersion, npmName);
if (lastVersion && semver.gt(lastVersion, currentVersion)) {
log.warn(colors.yellow(`请手动更新 ${npmName},当前版本:${currentVersion},最新版本:${lastVersion}
更新命令: npm install -g ${npmName}`));
}
}
'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);
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) ? 1 : -1);
}
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];
}
return null;
}
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;
}
module.exports = {
getNpmInfo,
getNpmVersions,
getNpmSemverVersion,
getDefaultRegistry,
getNpmLatestVersion,
};