作业

脚手架架构设计图

脚手架准备过程代码

主要函数

async function core() {
    try {
        // 检查 node 版本号
        checkNodeVersion();
        // root 降级
        checkRoot();
        // 检查主目录
        checkUserHome();
        // 检查入参
        checkInputArgs();
        // 检查环境变量
        checkEnv();
        // 检查更新
        await checkGlobalUpdate();
        // 命令
        commands(pkg);
    } catch (error) {
        log.error(colors.red(error.message));   
    }

}

检查node版本号

function checkNodeVersion() {
    const currentNodeVersion = process.version;
    const lowestVersion = constant.LOWEST_NODE_VERSION;
    if(semver.lt(currentNodeVersion, lowestVersion)) {
        throw new Error(colors.red(`需要安装 ${lowestVersion} 及以上版本的 node`));
    }
}

root 降级

function checkRoot() {
    const rootCheck = require('root-check');
    rootCheck();
}

检查主目录

function checkUserHome() {
    if (!userHome || !pathExists(userHome)) {
        throw new Error('当前用户主目录不存在!');
    }
}

检查入参

function checkInputArgs() {
    const minimist = require('minimist');
    args = minimist(process.argv.slice(2));
    checkArgs();
    log.verbose('debug', 'test deubug level');
}

检查更新

async function checkGlobalUpdate() {
    const currentVersion = pkg.version;
    const npmName = pkg.name;
    const lastVersion = await getNpmSemverVersion(currentVersion, npmName);
    if (lastVersion && semver.gt(lastVersion, currentVersion)) {
        log.warn(colors.yellow(`最新版本号:${lastVersion} 请使用 npm install -g ${npmName} 更新版本! 获得更好的使用体验!`));
    }
}

检查变量

function checkEnv() {
    const dotEnv = require('dotenv');
    const dotEnvPath = path.resolve(userHome);
    if (pathExists(dotEnvPath)) {
        config = dotEnv.config({
            path: dotEnvPath
        });
    }
    createDefaultConfig();
    log.verbose('环境变量', config);
}

创建默认配置

function createDefaultConfig() {
    const cLiConfig = {};
    if (process.env.FE_LAZY_CLI_HOME) {
        cLiConfig['feLazyCliHome'] = path.join(userHome, process.env.FE_LAZY_CLI_HOME);
    } else {
        cLiConfig['feLazyCliHome'] = path.join(userHome, constant.DEFAULT_CLI_HOME)
    }
    process.env.FE_LAZY_CLI_HOME = cLiConfig.feLazyCliHome;
}

检查是否开启debug模式

function checkArgs() {
    if (args.debug) {
        process.env.LOG_LEVEL = 'verbose';
    } else {
        process.env.LOG_LEVEL = 'info';
    }
    log.level = process.env.LOG_LEVEL;
}

通过 commander 框架实现一个脚手架,包含自定义 option 和 command 功能

文件头

'use strict';

const commander = require('commander');
const colors = require('colors');

const log = require('@fe-lazy-cli/log');
// 获取 commander 的单例
//  const { program } = commander;
// 手动实例化一个 commander
const program = new commander.Command();
module.exports = command;

脚手架主命令

function command(pkg) {
    program
        .name(Object.keys(pkg.bin)[0])
        .usage("<command> [option]")
        .version(pkg.version)
        .option('-d, --debug [debugModule]', '是否开启 debug 模式', false)
        .option('-v,  -V, --version', "输出版本信息");

    regCommand();
    regAddCommand();

    // 对未知命令进行提示
    program.on('command:*',(arg) => {
        let commands = program.commands.map(item => {
            return {
                name: item._name.split(''),
                consistency: 0
            };
        })
        commands = commands.map(item => {
            let argArr = arg[0].split('');
            let consistency = item.consistency
            item.name.map(c => {
                if (argArr.indexOf(c) >= 0) {
                    consistency ++;
                    argArr.splice(argArr.indexOf(c), 1);
                }
            })

            return {
                name: item.name.join(''),
                consistency
            };
        });
        commands = commands.filter(item => item.consistency > 0).sort((a, b) => b.consistency - a.consistency);
        commands = commands && commands.length && commands[0].name || false;

        let argText = arg[0] || "";
        if (commands) {
            throw new Error(colors.red(`抱歉!没有找到 '${argText}' 命令. 是否要运行 '${commands}' 命令. 或者运行 '${Object.keys(pkg.bin)[0]} --help' 查看帮助信息!`));
        }
        throw new Error(colors.red(`抱歉!没有找到 '${argText}' 命令. 请运行 '${Object.keys(pkg.bin)[0]} --help' 查看帮助信息!`));
    });


    program
        .parse(process.argv);
}

普通命令注册方式

function regCommand() {
    const echo = program.command('echo <envName> [argv]');

    echo
        .description('输出当前指令')
        .option('-t, --test', '配置', false)
        .action((envName, argv, option) => {
           log.info('测试输出', envName, argv, option.test);
        })
}

addCommand 命令注册方式


function regAddCommand() {
    const print = new commander.Command('print');

    print
        .alias('p')
        .description('输出指定数据')
        .command('int <number>')
        // .command(
        //     'init <number>', 
        //     '描述',  // 添加描述后 执行当前脚手架 + '-init'的脚手架: fe-lazy-cli-init
        //     {
        //         executableFile: 'fe', // 添加选项 执行 fe 脚手架
        //         isDefault: true, // 默认的执行命令
        //         hidden: true // 隐藏命令
        //     }
        // )
        .description('输出整数')
        .option('--hex <hexNumber>', '进制', 10)
        .action((number, option) => {
            log.info(`${option.hex} 进制`, parseInt(number, option.hex));
        });

    program.addCommand(print);
}

通过 webpack 和原生两种方式实现 node 对 es module 的支持

webpack + babel

安装 npm 包

    "@babel/core": "^7.12.10",
    "@babel/plugin-transform-runtime": "^7.12.10",
    "@babel/preset-env": "^7.12.11",
    "@babel/runtime-corejs3": "^7.12.5",
    "babel-loader": "^8.2.2",
    "webpack": "^5.13.0",
    "webpack-cli": "^4.3.1"

webpack.config.js

const path = require('path');
module.exports = {
    entry: './bin/core.js', // 入口文件
    mode: 'development', // 开发模式,development => 开发模式 production =》 生产模式
    output: { // 输出
        path: path.join(__dirname, '/dist'), // 输出目录
        filename: 'core.js' // 输出的文件名
    },
    target: 'node', // 默认web,因为需要使用到node原生模块,所以需要更改为node
    module: {
        rules: [{ // 配置babel-loader
        test: /\.js$/, // 处理js
        exclude: /(node_modules|dist)/, // 排除node_modules和dist目录
        use: {
          loader: 'babel-loader', // 使用babel对js进行低版本兼容处理
          options: {
            presets: ['@babel/preset-env'],
            plugins: [
              [
                '@babel/plugin-transform-runtime',
                {
                  'corejs': 3,
                  'regenerator': true,
                  "useESModules": true,
                  'helpers': true
                }]
            ]
          }
        }
        }]
    }
}

Node原生支持 ES Module

  1. 更改js文件后缀为.mjs
  2. import js的时候,不能省略后缀名
  3. 是实验性质特性,在node版本v14.x.x以后支持该特性
     node --experimental-modules ./index.mjs
    
Copyright © imooc-lego (2020 - present) all right reserved,powered by GitbookFile Modify: 2021-06-27 08:04:56

results matching ""

    No results matching ""