如何写一个项目初始化工具(中)

158 阅读2分钟

「这是我参与2022首次更文挑战的第37天,活动详情查看:2022首次更文挑战

上一篇中,我们实现了一个只能输出日志的 generator,这篇我们来丰富一下功能。

用户交互 this.prompt

通过 prompt 可以实现用户交换,譬如获取用户输入、用户确认等基本操作。prompt 是个异步方法,参数为一个数组,数组中是要执行的交互操作。

交互操作对象

  • type:交互类型(值可以是 input:输入,confirm:选择等);
  • name:接收输入信息的变量名;
  • message:命令行中输出的提示信息;
  • default:输入的默认值;

我们把原来的 method1、method2 方法删除,换成下面的代码。

module.exports = class extends Generator {
    constructor(args, opts) {
        // Calling the super constructor is important so our generator is correctly set up
        super(args, opts);
    }

    async setup() {
        const ans = await this.prompt([{
            type: 'input',
            name: 'name',
            message: 'Your project name.',
            default: this.appname
        }, {
            type: 'confirm',
            name: 'cool',
            message: 'Would you like to enable the Cool feature?'
        }])

        this.log('app name:', ans.name)
        this.log('cool featrue:', ans.cool)
    }
};

再次执行 yo createapp

Kapture 2022-02-22 at 15.46.54.gif

至此我们就完成了用户输入工作,通常的项目名称等需要收集用户输入信息。

文件系统,模板的使用

我们通常会将基础模块放在模板里,完成基础配置,然后使用模板来创建项目,下面我们来看 yeoman 的模板怎么使用。

第一步:在 generators 录下创建一个 templates 目录,用于存放模板。然后在 templates 创建 index.html 文件,加入以下代码

<html>
    <head>
        <title><%= appname %></title>
    </head>
    <body>Hello World.</body>
</html>

第二步:修改 generators/app/index.js 文件的代码如下

var Generator = require('yeoman-generator');

module.exports = class extends Generator {
    constructor(args, opts) {
        // Calling the super constructor is important so our generator is correctly set up
        super(args, opts);
    }

    async setup() {
        const ans = await this.prompt([{
            type: 'input',
            name: 'name',
            message: 'Your project name.',
            default: this.appname
        }])

        this.fs.copyTpl(this.templatePath('index.html'), this.destinationPath('public/index.html'), {
            appname: ans.name
        })
    }
};

这里的 this.fs.copyTpl 可以用来拷贝一个模板到指定位置,并且带上替换模板文件中的变量对应的参数。this.templatePath 用于将一个相对路径转换成模板文件下的路径。this.destinationPath 用于将一个相对路径转换成输出的绝对路径。

第三步:执行 yo createapp 命令,输入 vue3

执行命令后,生成 /public/index.html 文件,并且用 vue3 替换模板文件中的 <%= appname %>。生成的文件如下

<html>
    <head>
        <title>vue3</title>
    </head>
    <body>Hello World.</body>
</html>

管理依赖

项目的依赖可以在 template 里增加 package.json 文件,也可以通过编程的方式创建该文件。

generators/app/index.js 文件中增加以下方法,this.fs.extendJSON() 创建 package.json 文件。

initPackage() {
    const pkgJson = {
        DevDependencies: {
            eslint: '^3.15.0'
        },
        Dependencies: {
            vue: '^3.2.31'
        }
    }

    this.fs.extendJSON(this.destinationPath('public/package.json'), pkgJson)
    this.npmInstall()
}

npmInstall 方法可以自动安装依赖,但该方法在 yeoman 5.0 后已经 deprecated 了,使用时需要注意 yeoman 当前版本

至此我们完成了初始化工具的雏形,下一节来改造成 vue 项目的 generator。