• 手摸手教你搭个脚手架


    目录

    1. 脚手架
    2. 全局命令
    3. 交互式输入
    4. 拉取远程仓库代码
    5. 优化
    6. 总结

    1、脚手架

    今天工地的砖有点烫,我抬头望了望天,思考了半分钟,决定为了以后搬砖方便,先搭个脚手架:

    不好意思,拿错了,是这个:

    相信很多小伙伴都用过vue-cli、create-react-app或angular-cli之类的脚手架,一个命令行就能快速搭起项目框架,告别刀耕火种的复制粘贴,分分钟解放生产力。

    作为一个有追求的切图仔,这种摸鱼神器,必须立马安排。

    好了,那么问题来了:什么是脚手架?

    从表现形式上来看,脚手架主要有以下几个特点:

    1. 一个能全局执行的命令;
    2. 能实现交互式输入,比如输入项目名称,选择配置项等;
    3. 能自动拉取github或gitlab远程仓库的代码。

    当然高级的脚手架肯定不止这么点功能,不过我们先从最简单的实现起。

    2、全局命令

    2.1 基本原理

    先拆包观察一下,类似vue-cli这类的全局命令是如何实现的。
    首先找到vue-cli的安装路径,全局安装可以通过npm config get prefix找到路径,比如我的windows系统就是
    C:Users用户名AppDataRoaming pm:

    可以看到这个目录下有很多与全局命令同名的文件,以及一个node_modules文件夹。我们全局安装的依赖包就在node_modules里。找到@vuecli,这个就是vue-cli的源码包。

    vue-cli的源码目录

    vue-cli源码包中的package.json有这样一个关键配置:

      "bin": {
        "vue": "bin/vue.js"
      },
    

    这个bin/vue.js脚本必须以#!/usr/bin/env node开头,

    当npm全局安装时,就会根据这个配置,生成对应的同名可执行文件。

    而当我们运行vue时,系统就会以node程序来运行vue.js。

    npm官方文档中提供了npm link命令,用以让用户将自定义的脚手架生成一个全局命令。

    npm link主要做了两步操作:

    • 一是在npm全局安装路径下的node_modules文件夹里生成一个链接文件,这个链接文件指向执行该命令的文件夹,也就是我们的脚手架源码文件夹;
    • 二是在npm全局安装路径下生成与配置bin里同名的可执行文件。

    所以,通过npm link,我们就可以生成一个node全局命令

    npm link官方文档:https://docs.npmjs.com/cli/v6/commands/npm-link。

    2.2 全局命令的实现

    话不多说,先来撸一个全局命令。

    1)执行npm init初始化一个package.json

    2)在package.json里加上bin配置:

      "bin": {
        "test-cli": "./test.js"
      },
    

    3)添加对应的执行脚本文件test.js

    #! /usr/bin/env node
    console.log("Hello! My CLI!");
    

    4)在package.json同级目录下执行npm link

    5)在控制台运行一下我们定义的全局命令test-cli,看到输出结果:

    全局命令生效

    完成!

    3、交互式输入

    通过上述操作,用户已经可以通过全局命令执行到我们的test.js文件,剩下的功能我们就可以在js里去自由发挥了。

    Node社区有着数量庞大的第三方模块,藉由这些模块我们可以快速开发实现想要的功能。

    inquirier就是其中之一,目前在github上有14.5k的star,它的目标就是“致力于成为一个易于嵌入且美观的命令行工具”。顾名思义,通过inquirier模块,我们可以在命令行中实现与用户的输入交互。

    我们需要知道用户要创建的项目名称是什么,以及用户想要下载哪个远程仓库的代码:

    const inquirer = require("inquirer");
    
    inquirer
        .prompt([
            {
                type: "input",
                name: "project",
                message: "项目名称",
            },
            {
                type: "list",
                name: "tpl",
                message: "请选择模板",
                choices: ["vue", "react"],
            }
        ])
        .then((res) => {
            console.log(res);
            const { project, tpl } = res;
            // project就是用户输入的项目名称
            // tpl就是用户选择的模板
        });
    

    这段代码就是为用户提供了一个input输入选项,来输入项目名称,以及一个list列表选项,来选择要下载的模板(之后我们再根据这个模板名称去对应的仓库地址进行下载)。

    inquirer交互效果

    inquirer还有更多的选项功能,感兴趣的小伙伴可以去官方文档上自由探索:https://github.com/SBoudrias/Inquirer.js。

    4、拉取远程仓库代码

    现在我们已经知道用户要下载的是哪个模板代码,也知道这些模板代码对应的下载地址:

    const stores = [
        {
            name: "vue",
            url: "https://github.com/vuejs/vue.git"
        },
        {
            name: "react",
            url: "https://github.com/facebook/react.git"
        }
    ]
    

    拉取github或者gitlab远程仓库代码的第三方模块也有好几个,我选用的是nodegit,这个项目在github上目前有4.9k的star,用起来也很简单:

    const Git = require("nodegit");
    
    /** 克隆远程仓库代码 */
    // url: 源码仓库地址; path: 要下载的目标路径; cb: 下载结束后的回调函数
    const gitClone = (url, path, cb)=>{
        console.log("正在下载远程仓库代码...")
        console.log(url)
        Git.Clone(url, path)
           .then(function(res) {
                console.log("下载完成")
                cb(true)
            })
            .catch(function(err) { console.log("下载失败"+err);cb(false) });
    }
    

    nodegit官网地址:
    https://github.com/nodegit/nodegit

    至此三个基本功能都已实现!

    5、优化

    深谙摸鱼之道的我想了想,觉得还能更进一步,比如下载完源码,再帮我自动安装下依赖包啦:

    const process = require('child_process');
    
    /** 安装依赖包 */
    const install = (path)=>{ // path是源码模板中package.json所在的路径
        console.log("正在安装依赖包...")
        const cmd = 'cd '+path+' && yarn';
        process.exec(cmd, function(error, stdout, stderr) {
            console.log(error);
            console.log(stdout);
            console.log(stderr);
            console.log("安装完成")
        });
    }
    

    愉快地摸会儿鱼

    之前看到很多脚手架出场都自带拉风的艺术字,作为一个有追求的切图仔,这个必须安排!
    这个也是用到了一个第三方模块figlethttps://github.com/patorjk/figlet.js):

    const figlet = require('figlet');   
    figlet('My CLI!', {horizontalLayout:"full"}, function(err, data) {
        if (err) {
            console.log('Something went wrong...');
            console.dir(err);
            return;
        }
        console.log(data)
        // do something...
    });
    

    瞬间高大上有木有o

    很多脚手架还提供了参数配置、帮助信息等功能,这个大多是通过commander模块实现的(https://github.com/tj/commander.js,20.7k star),这里就不详细展开了,我在demo项目里也简单实现了下,确实很强大很好用。

    Demo已开源:https://github.com/youzouzou/testcli

    这个demo只是简单地实现了脚手架的基本功能,探索了一下几个node模块的用法,还有很多需要优化的点。进一步学习的最好办法就是去看那些成熟的脚手架源码,然后去模仿去实践,再结合实际情况,摸索出最适合自己团队的方案。

    6、总结

    工欲善其事,必先利其器。

    实际上脚手架并不拘泥于上面的实现形式,凡是能提高效率的工具,在某种意义上都可以称之为脚手架。

    模仿只是最初级的阶段,创新才是真正的开始。

  • 相关阅读:
    LINQ/EF/Lambda 比较字符串日期时间大小
    WinForm RDLC SubReport Step by step
    centos7安装7-zip
    centos修改命令提示符颜色
    更换官方zabbix.repo为阿里云镜像
    利用shell脚本清理nginx日志
    docker
    centos 建立静态 IP 与 IP 地址丢失的解决办法
    构建lnmp高可用架构
    keepalived高可用
  • 原文地址:https://www.cnblogs.com/wl-blog/p/15000803.html
Copyright © 2020-2023  润新知