前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >手把手教你写一个脚手架(二)

手把手教你写一个脚手架(二)

作者头像
谭光志
发布2022-03-24 08:18:41
6890
发布2022-03-24 08:18:41
举报

时隔三个月,终于有时间写脚手架系列第二篇文章了,在北京上班确实比天津忙多了,都没时间摸鱼。如果你没看过本系列的第一篇文章手把手教你写一个脚手架,建议先看一遍再来阅读本文,效果更好。

mini-cli 项目 github 地址:https://github.com/woai3c/min...

v3 版本的代码在 v3 分支,v4 版本的代码在 v4 分支。

第三个版本 v3

第三个版本主要添加了两个功能:

  1. 将项目拆分为 monorepo 的组织方式。
  2. 新增 add 命令,可以通过 mvc add xxx 命令的方式来添加插件。

monorepo

首先来简单了解一下 monorepo 和 multirepo。它们都是项目管理的一种方式,multirepo 就是将不同的项目放在不同的 git 仓库维护,而 monorepo 将多个项目放在同一个 git 仓库中维护。在 v3 版本里,我要将 mini-cli 改造成 monorepo 的方式,把不同的插件当成一个个独立的项目来维护。

在将项目改造成 monorepo 后,目录如下所示:

├─packages
│  ├─@mvc
│  │  ├─cli # 核心插件
│  │  ├─cli-plugin-babel # babel 插件
│  │  ├─cli-plugin-linter # linter 插件
│  │  ├─cli-plugin-router # router 插件
│  │  ├─cli-plugin-vue # vue 插件
│  │  ├─cli-plugin-vuex # vuex 插件
│  │  └─cli-plugin-webpack # webpack 插件
└─scripts # commit message 验证脚本 和项目无关 不需关注
│─lerna.json
|─package.json
monorepo 改造过程

全局安装 lerna

npm install -g lerna

创建项目

git init mini-cli

初始化

cd mini-cli
lerna init

创建 package

lerna create xxx

由于 cli 是脚手架核心代码,在这里需要调用其他插件,因为要将其他插件添加到 @mvc/cli 的依赖项

# 如果是添加到 devDependencies,则需要在后面加上 --dev
# 下载第三方依赖也是同样的命令
lerna add @mvc/cli-plugin-babel --scope=@mvc/cli

改造成 monorepo-repo 后的脚手架功能和第二版没有区别,只是将插件相关的代码独立成一个单独的 repo,后续可以将插件单独发布到 npm。

使用 monorepo 的优点
  1. 如果采用 multirepo 的方式开发,在本地调试时如果需要调用其他插件,则需要先执行 npm i 安装,才能使用。采用 monorepo 则没有这种烦恼,可以直接调用在 packages 目录里的其他插件,方便开发调试。
  2. 如果多个插件都进行了修改,执行 lerna publish 时可以同时发布已经修改过的插件,不用每个单独发布。

add 命令

将项目改造成 monorepo-repo 的目的就是为了后续方便做扩展。例如生成的项目原来是不支持 router 的,在中途突然想加入 router 功能,就可以执行命令 mvc add router 添加 vue-router 依赖以及相关的模板代码。

先来看一下 add 命令的代码:

const path = require('path')
const inquirer = require('inquirer')
const Generator = require('./Generator')
const clearConsole = require('./utils/clearConsole')
const PackageManager = require('./PackageManager')
const getPackage = require('./utils/getPackage')
const readFiles = require('./utils/readFiles')

async function add(name) {
    const targetDir = process.cwd()
    const pkg = getPackage(targetDir)
    // 清空控制台
    clearConsole()

    let answers = {}
    try {
        const pluginPrompts = require(`@mvc/cli-plugin-${name}/prompts`)
        answers = await inquirer.prompt(pluginPrompts)
    } catch (error) {
        console.log(error)
    }

    const generator = new Generator(pkg, targetDir, await readFiles(targetDir))
    const pm = new PackageManager(targetDir, answers.packageManager)
    require(`@mvc/cli-plugin-${name}/generator`)(generator, answers)

    await generator.generate()
    // 下载依赖
    await pm.install()
}

module.exports = add

由于 v3 版本仍然是在本地开发的,所以没有将相关插件发布到 npm 上,因为可以直接引用插件,而不需执行 npm i 安装。在 v2 版本执行 create 命令创建项目时,所有的交互提示语都是放在 cli 插件下的,但是 add 命令是单独添加一个插件,因此还需要在每个插件下添加一个 prompts.js 文件(如果不需要,可以不加),里面是一些和用户交互的语句。例如用 add 命令添加 router 插件时,会询问是否选择 history 模式。

const chalk = require('chalk')

module.exports = [
    {
        name: 'historyMode',
        type: 'confirm',
        message: `Use history mode for router? ${chalk.yellow(`(Requires proper server setup for index fallback in production)`)}`,
        description: `By using the HTML5 History API, the URLs don't need the '#' character anymore.`,
    },
]

从 add 命令的代码逻辑可以看出来,如果新加的插件有 prompts.js 文件就读取代码弹出交互语句。否则跳过,直接进行下载。

第四个版本 v4

v4 版本主要将 webpack 的 dev 和 build 功能做成了动态,原来的脚手架生成的项目是有一个 build 目录,里面是 webpack 的一些配置代码。v4 版本的脚手架生成的项目是没有 build 目录的。

这一个功能通过新增的 mvc-cli-service 插件来实现,生成的项目中会有以下两个脚本命令:

scripts: {
    serve: 'mvc-cli-service serve',
    build: 'mvc-cli-service build',
},

当运行 npm run serve 时,就会执行命令 mvc-cli-service serve。这一块的代码如下:

#!/usr/bin/env node
const webpack = require('webpack')
const WebpackDevServer = require('webpack-dev-server')
const devConfig = require('../lib/dev.config')
const buildConfig = require('../lib/pro.config')

const args = process.argv.slice(2)
if (args[0] === 'serve') {
    const compiler = webpack(devConfig)
    const server = new WebpackDevServer(compiler)

    server.listen(8080, '0.0.0.0', err => {
        console.log(err)
    })
} else if (args[0] === 'build') {
    webpack(buildConfig, (err, stats) => {
        if (err) console.log(err)
        if (stats.hasErrors()) {
            console.log(new Error('Build failed with errors.'))
        }
    })
} else {
    console.log('error command')
}

原理如下(npm scripts 使用指南):

npm 脚本的原理非常简单。每当执行npm run,就会自动新建一个 Shell,在这个 Shell 里面执行指定的脚本命令。因此,只要是 Shell(一般是 Bash)可以运行的命令,就可以写在 npm 脚本里面。 比较特别的是,npm run新建的这个 Shell,会将当前目录的node_modules/.bin子目录加入PATH变量,执行结束后,再将PATH变量恢复原样。

上述代码对执行的命令进行了判断,如果是 serve,就 new 一个 WebpackDevServer 实例启动开发环境。如果是 build,就用 webpack 进行打包。

vue-cli 的 webpack 配置是动态的,使用了 chainwebpack 来动态添加不同的配置,我这个 demo 是直接写死的,主要是没时间,所以没有再深入研究。

发布到 npm 后

下载 mini-cli 脚手架,其实下载的只是核心插件 mvc-cli。如果这个插件需要引用其他插件,则需要先进行安装,再调用。因此对 create add 命令需要做一些修改。下面看一下 create 命令代码的改动:

answers.features.forEach(feature => {
    if (feature !== 'service') {
        pkg.devDependencies[`mvc-cli-plugin-${feature}`] = '~1.0.0'
    } else {
        pkg.devDependencies['mvc-cli-service'] = '~1.0.0'
    }
})

await writeFileTree(targetDir, {
    'package.json': JSON.stringify(pkg, null, 2),
})

await pm.install()

// 根据用户选择的选项加载相应的模块,在 package.json 写入对应的依赖项
// 并且将对应的 template 模块渲染
answers.features.forEach(feature => {
    if (feature !== 'service') {
        require(`mvc-cli-plugin-${feature}/generator`)(generator, answers)
    } else {
        require(`mvc-cli-service/generator`)(generator, answers)
    }
})

await generator.generate()

// 下载依赖
await pm.install()

上面的代码就是新增的逻辑,在用户选择完需要的插件后,将这些插件写入到 pkg 对象,然后生成 package.json 文件,再执行 npm install 安装依赖。安装完插件后,再读取每个插件的 generator 目录/文件代码,从而生成模板或再次添加不同的依赖。然后再执行一次安装。

发布遇到的坑

v3 版本的插件有一个前缀 @mvc,由于带有 @ 前缀的 npm 包会默认作为私人包,因此遇到了一些坑。花费了挺长的时间,后来懒得弄了,干脆将所有的插件重新改了前缀名,变成 mvc 开头的前缀。

参考资料

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第三个版本 v3
    • monorepo
      • monorepo 改造过程
      • 使用 monorepo 的优点
    • add 命令
    • 第四个版本 v4
      • 发布到 npm 后
        • 发布遇到的坑
        • 参考资料
        相关产品与服务
        项目管理
        CODING 项目管理(CODING Project Management,CODING-PM)工具包含迭代管理、需求管理、任务管理、缺陷管理、文件/wiki 等功能,适用于研发团队进行项目管理或敏捷开发实践。结合敏捷研发理念,帮助您对产品进行迭代规划,让每个迭代中的需求、任务、缺陷无障碍沟通流转, 让项目开发过程风险可控,达到可持续性快速迭代。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档