脚手架核心流程开发

脚手架整体架构设计


前端开发过程中的痛点和需求分析

痛点

  • 存在大量重复代码的拷贝
  • 协同开发时,分支混乱, 操作不规范,导致耗时
  • 发布上线耗时,会出现各种各样的错误

需求分析

1.通用的组件/模板创建能力

  • 模板支持定制,定制后能发布生效
  • 模板支持快速接入,极低的接入成本

    2.通用的项目/组件发布能力

  • 发布过程中自动完成标准的 git 操作

  • 发布完成后自动删除开发分支并创建 tag
  • 发布后自动完成云构建、cdn、域名绑定
  • 发布过程支持测试/正式两种模式

大厂是如何做项目的

自己动手画了一下示意图

git 操作规范

自己动手画了一下示意图

架构设计图

脚手架模块拆分策略

拆包原则

根据模块的功能来拆分:

  • core: 核心模块
  • utils: 工具模块
  • commands: 命令模块
  • models: 模型模块

拆包结果

  1. 核心流程:core
  2. 命令模块:commands
    • 初始化
    • 发布
    • 清除缓存
  3. 模型: models
    • Command 命令
    • Project 项目
    • Component 组件
    • Npm 模块
    • Git 仓库
  4. 支撑层: utils
    • Git 操作
    • 云构建
    • 工具方法
    • API 请求
    • Git API

core 模块技术方案

core 模块的技术方案主要分为三个阶段,分别是准备阶段、命令注册、命令执行。第三周的课程内容主要是讲准备阶段。


涉及到的技术点

核心库

  • import-local
  • commander

工具库

  • fs-extra (用于文件操作,基于 fs 封装的库)
  • dotenv (可以获取到环境变量)
  • semver (比较 package 的版本)
  • root-check (进行 root 降级)
  • user-home (拿到用户主目录)
  • colors (可以在终端当中打印不同颜色的文本)
  • npmlog (打印日志用,可以进行定制)

实现脚手架准备过程

检查版本号

思路:直接引用 package.json 文件,获取其中的 version 字段,打印到终端。注意:这里打印的时候可以使用 console.log,也可以使用 npmlog 这个依赖库。

const pkg = require('../package.json')
function checkVersion() {
    console.log(pkg.version)
    // or
    log.info(pkg.version)
}

检查 Node 版本

思路: 获取当前的 node 版本,和我们事先预设好的版本进行比对,如果当前版本较低,那么给用户一个提示。

const semver = require('semver')
const colors = require('colors/safe')
function checkNodeVersion() {
    // 获取当前的 node 版本
    const currentVersion = process.version
    // 和我们事先预设好的版本进行比对
    const lowestVersion = constant.LOWET_NODE_VERSION
    // 如果当前版本较低,那么给用户一个提示
    if (!semver.gte(currentVersion, lowestVersion)) {
        throw new Error(colors.red(`tangmen-cli 需要安装${lowestVersion}版本及以上的Node.js`))
    }
}

检查 root 是否启动

思路:这个功能比较简单,事情都让 root-check 这个库帮我们做了,我们只需要引用并且调用一下就可以实现 root 降级,规避掉因为 root 用户带来的一系列权限问题。

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

检查用户主目录

const userHome = require('user-home')
const pathExists = require('path-exists').sync
function checkUserHome() {
    if (!userHome || !pathExists(userHome)) {
        throw new Error(colors.red('当前用户主目录不存在,请检查!'))
    }
}

检查入参

let args
function checkInputArgs() {
    args = require('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
}

检查环境变量的两种实现方式

function checkEnv() {
    const dotenv = require('dotenv')
    const dotenvPath = path.resolve(userHome, '.env')
    if (pathExists(dotenvPath)) {
        dotenv.config({
            path: dotenvPath
        })
    }
    createDefaultConfig()
    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, constant.DEFAULT_CLI_HOME)
    }
    process.env.CLI_HOME_PATH = cliConfig.cliHome
}
function checkEnv() {
    const dotenv = require('dotenv')
    const dotenvPath = path.resolve(userHome, '.env')
    if (pathExists(dotenvPath)) {
        config = dotenv.config({
            path: dotenvPath
        })
    }
    config = createDefaultConfig()
    log.verbose('环境变量', config, process.env.CLI_HOME)
}
// 创建默认的环境变量配置
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)
    }
    return cliConfig
}

检查是否为最新版本

async function checkGlobalUpdate() {
    // 获取当前用户安装的版本是多少
    const currentVersion = pkg.version
    const npmName = pkg.name
    // 通过接口请求拿到最新的版本号
    const { getNpmSemverVersion } = require('@tangmen-cli-dev/get-npm-info')
    const latestVersion = await getNpmSemverVersion(currentVersion, npmName)
    // 拿npm上最新的版本号和本地安装的版本号进行对比,如果前者大于后者,则给用户一个明显的提示
    if (latestVersion && semver.gt(latestVersion, currentVersion)) {
        log.warn(
            colors.yellow(`请手动更新${npmName}, 当前版本:${currentVersion}, 最新版本: ${latestVersion}
                  更新命令: npm install -g ${npmName}
        `)
        )
    }
}

本周作业完成情况

  1. 绘制脚手架架构设计图(已完成)
  2. 实现脚手架准备过程代码(已完成)
  3. 通过 commander 实现一个脚手架,包含自定义 option 和 command 功能:npm i -g imooc-test-erdan(已完成)
  4. 通过 webpack 和原生两种方式实现 Node 对 ES Module 的支持(已完成)
Copyright © imooc-lego (2020 - present) all right reserved,powered by GitbookFile Modify: 2021-02-06 00:45:57

results matching ""

    No results matching ""