Plop 简介

Prompts:让生成器向你提问

掌握 Plop 中常用的交互式提问类型,包括输入、确认、单选、多选、默认值和校验。

🎯 引言

学完这篇文章,你将掌握 Plop 中 prompts 的常用写法。通过不同类型的问题,你可以让生成器在运行前收集必要的信息,比如文件名、是否创建样式文件、选择组件类型等。


🧱 prompts 的基本结构

prompts 是一个数组,每个元素是一个问题对象。Plop 底层使用 Inquirer 来实现命令行交互。

一个基本的问题对象包含这些字段:

{
    type: 'input',       // 问题类型
    name: 'name',        // 答案在模板中使用的变量名
    message: '请输入名称', // 显示给用户的提示文字
    default: 'MyComponent' // 默认值(可选)
}

用户回答后,答案会以 name 为键存储,在模板中通过 {{name}} 使用。


✨ 常用提问类型

input:文本输入

最常用的问题类型,适合获取名称、路径等字符串。

{
    type: 'input',
    name: 'name',
    message: '请输入组件名称'
}

confirm:是 / 否

适合询问“是否需要某个可选文件”。

{
    type: 'confirm',
    name: 'hasStyle',
    message: '是否需要创建样式文件?',
    default: true
}

在模板中,hasStyle 的值是布尔类型。可以直接配合 {{#if hasStyle}} 使用。

list:单选

适合让用户从固定选项中选择一个。

{
    type: 'list',
    name: 'type',
    message: '请选择组件类型',
    choices: ['基础组件', '业务组件', '布局组件'],
    default: '基础组件'
}

checkbox:多选

适合让用户一次性选择多个选项。

{
    type: 'checkbox',
    name: 'features',
    message: '请选择需要生成的文件',
    choices: ['script', 'style', 'test'],
    default: ['script', 'style']
}
checkbox 返回的是一个数组。在模板中可以用 {{#each features}} 循环遍历。

🛠 综合示例:生成组件时询问多个问题

下面我们写一个更贴近实际的生成器,创建组件时同时询问名称、类型和是否需要样式:

plopfile.mjs
export default function (plop) {
    plop.setGenerator('component', {
        description: '创建一个 Vue 组件',
        prompts: [
            {
                type: 'input',
                name: 'name',
                message: '请输入组件名称'
            },
            {
                type: 'list',
                name: 'type',
                message: '请选择组件类型',
                choices: ['base', 'business', 'layout'],
                default: 'base'
            },
            {
                type: 'confirm',
                name: 'hasStyle',
                message: '是否需要创建样式文件?',
                default: true
            }
        ],
        actions: [
            {
                type: 'add',
                path: 'src/components/{{pascalCase name}}.vue',
                templateFile: 'plop-templates/component.hbs'
            }
        ]
    });
}

模板文件:

plop-templates/component.hbs
<template>
    <div class="{{kebabCase name}}">
        {{pascalCase name}} 组件
    </div>
</template>

<script setup>
// 组件类型:{{type}}
</script>

{{#if hasStyle}}
<style scoped>
.{{kebabCase name}} {
    /* {{type}} 组件样式 */
}
</style>
{{/if}}

运行后,如果选择需要样式,生成的文件会包含 <style> 块;否则不会。


⚡ 默认值与校验

default:给出默认答案

{
    type: 'input',
    name: 'name',
    message: '请输入组件名称',
    default: 'MyComponent'
}

用户直接回车就会使用 MyComponent

validate:校验输入

{
    type: 'input',
    name: 'name',
    message: '请输入组件名称',
    validate: function (value) {
        if (value.trim() === '') {
            return '组件名称不能为空';
        }
        if (!/^[A-Z][a-zA-Z0-9]*$/.test(value)) {
            return '组件名称必须以英文大写字母开头';
        }
        return true;
    }
}

如果校验返回字符串,Plop 会把它当错误信息显示出来;返回 true 表示通过。


💡 根据上一题答案动态显示问题

使用 when 可以让某个问题只在特定条件下出现。

{
    type: 'confirm',
    name: 'hasTest',
    message: '是否需要生成测试文件?',
    default: false
},
{
    type: 'input',
    name: 'testName',
    message: '请输入测试文件名称',
    when: function (answers) {
        return answers.hasTest;
    }
}

只有当用户选择“需要测试文件”时,才会继续询问测试文件名称。


🧾 小节总结

  • prompts 是问题数组,每个问题包含 typenamemessage 等字段。
  • 常用类型有 input(文本)、confirm(确认)、list(单选)、checkbox(多选)。
  • default 可以设置默认值,validate 可以校验用户输入。
  • when 可以根据前面的答案决定是否显示当前问题。

❓ 知识问答

Q1:name 字段有什么作用?

A:name 是答案的变量名。用户回答的内容会保存在这个名下,模板中通过 {{name}} 使用。

Q2:confirm 类型返回什么值?

A:返回 truefalse。可以直接在 Handlebars 模板中用 {{#if hasStyle}} 做条件判断。

Q3:listcheckbox 有什么区别?

A:list 是单选,返回一个字符串;checkbox 是多选,返回一个数组。

Q4:校验函数返回字符串和 true 分别代表什么?

A:返回字符串表示校验失败,字符串内容会作为错误提示显示;返回 true 表示校验通过。


🧪 小练习

请为 component 生成器增加一个问题:询问是否需要生成 props 定义。

{
    type: 'confirm',
    name: 'hasProps',
    // 请在这里补全 message 和 default
}

然后在 component.hbs 模板中使用它:

{{#if hasProps}}
<script setup>
// 请在这里补全 props 定义代码
</script>
{{/if}}

🎉 恭喜你掌握了 Plop 的交互式提问!下一篇我们会学习 actions,了解生成器可以执行哪些具体动作。