Plop 简介

Actions:生成器能执行哪些动作

掌握 Plop 的 add、modify、addMany 等核心动作,学会用它们创建、修改和批量生成文件。

🎯 引言

学完这篇文章,你将掌握 Plop 中最常用的几个动作:add 创建文件、modify 修改文件、addMany 批量创建文件。它们是每个生成器的“执行引擎”。


🧱 actions 的基本结构

actions 是一个数组,每个元素描述一个要执行的动作。Plop 会按顺序依次执行。

actions: [
    {
        type: 'add',
        path: 'src/components/{{pascalCase name}}.vue',
        templateFile: 'plop-templates/component.hbs'
    }
]

每个动作至少有 type 字段,不同的 type 对应不同的行为。


✨ add:创建单个文件

add 是最常用的动作,用于根据模板创建一个新文件。

{
    type: 'add',
    path: 'src/components/{{pascalCase name}}.vue',
    templateFile: 'plop-templates/component.hbs'
}
字段说明
path生成的目标文件路径,支持模板变量
templateFile模板文件路径
template直接写模板字符串(与 templateFile 二选一)

如果不想单独维护模板文件,也可以直接写 template

{
    type: 'add',
    path: 'src/components/{{pascalCase name}}.vue',
    template: '<template>\n    <div>{{name}}</div>\n</template>\n'
}
模板文件更适合复杂内容,直接写 template 适合一两行的简单片段。

✨ modify:修改已有文件

modify 用来在已有文件里查找并替换内容,适合往已有目录或配置里追加内容。

{
    type: 'modify',
    path: 'src/router/index.js',
    pattern: /\/\/ 请在这里导入路由/,
    template: "import {{pascalCase name}} from '@/views/{{pascalCase name}}.vue';\n// 请在这里导入路由"
}

上面的例子会在 // 请在这里导入路由 这一行的前面插入一条 import 语句。

字段说明
path要修改的文件路径
pattern用于匹配替换位置的正则表达式或字符串
template替换后的内容
templateFile也可以从文件读取替换内容
使用 modify 时要特别小心 pattern 的写法。如果匹配失败,原文件不会被修改,建议先在副本上测试。

✨ addMany:批量创建文件

当一次需要生成多个相关文件时,用 addMany 可以简化配置。

{
    type: 'addMany',
    destination: 'src/components/{{pascalCase name}}',
    templateFiles: 'plop-templates/component/**'
}

假设 plop-templates/component/ 目录下有以下文件:

plop-templates/component/
├── index.vue
├── index.js
└── style.scss

执行后会在 src/components/UserInfo/ 下生成对应的 index.vueindex.jsstyle.scss

字段说明
destination目标目录
templateFiles模板文件匹配规则,支持通配符
base去掉模板路径中的前缀目录
如果希望生成的文件不包含 component 这一层目录,可以加 base: 'plop-templates/component'

🛠 综合示例:组件 + 样式 + 路由注册

下面这个生成器会同时完成三件事:

  1. 创建组件文件。
  2. 创建样式文件。
  3. 在路由文件里自动导入新页面。
plopfile.mjs
export default function (plop) {
    plop.setGenerator('page', {
        description: '创建一个页面并注册路由',
        prompts: [
            {
                type: 'input',
                name: 'name',
                message: '请输入页面名称'
            }
        ],
        actions: [
            {
                type: 'add',
                path: 'src/views/{{pascalCase name}}Page.vue',
                templateFile: 'plop-templates/page.hbs'
            },
            {
                type: 'add',
                path: 'src/views/{{pascalCase name}}Page.scss',
                templateFile: 'plop-templates/page.scss.hbs'
            },
            {
                type: 'modify',
                path: 'src/router/index.js',
                pattern: /\/\/ 请在这里导入页面/,
                template: "import {{pascalCase name}}Page from '@/views/{{pascalCase name}}Page.vue';\n// 请在这里导入页面"
            }
        ]
    });
}
动作的 pathtemplate 里都支持 Handlebars 变量。你可以把同一个 namepascalCasekebabCasecamelCase 等不同格式渲染。

⚡ abortOnFail:动作失败时是否停止

默认情况下,如果某个动作执行失败,Plop 会停止后续动作。你可以通过 abortOnFail 控制这个行为。

{
    type: 'add',
    path: 'src/components/{{pascalCase name}}.vue',
    templateFile: 'plop-templates/component.hbs',
    abortOnFail: false
}

设为 false 后,即使这个动作失败,Plop 也会继续执行后面的动作。


💡 skip 函数:动态决定是否执行

每个动作还可以加 skip 函数,根据用户答案决定是否跳过。

{
    type: 'add',
    path: 'src/components/{{pascalCase name}}.test.js',
    templateFile: 'plop-templates/test.hbs',
    skip: function (answers) {
        if (!answers.hasTest) {
            return '跳过测试文件生成';
        }
    }
}

如果 skip 返回字符串,这个动作就会被跳过,并显示提示信息。


🧾 小节总结

  • add 用于创建单个文件,是最常用的动作。
  • modify 用于修改已有文件内容,适合追加导入、注册路由等场景。
  • addMany 用于批量创建一组文件。
  • abortOnFail 控制动作失败时是否停止。
  • skip 函数可以动态决定是否执行某个动作。

❓ 知识问答

Q1:addtemplatetemplateFile 有什么区别?

A:template 直接写模板字符串,templateFile 从文件读取模板内容。复杂模板推荐用 templateFile

Q2:modify 会覆盖整个文件吗?

A:不会。它只替换 pattern 匹配到的部分,其余内容保持不变。

Q3:addManydestinationpath 有什么区别?

A:addpath 指定单个文件;addManydestination 指定目标目录,会根据模板目录批量生成多个文件。

Q4:多个动作是按顺序执行的吗?

A:是的。actions 数组里的动作会按顺序依次执行。


🧪 小练习

请补全下面的动作配置,让它在创建组件的同时,自动创建一个同名的测试文件:

{
    type: 'add',
    path: 'src/components/{{pascalCase name}}.vue',
    templateFile: 'plop-templates/component.hbs'
},
// 请在这里添加一个动作,生成 src/components/{{pascalCase name}}.test.js

🎉 恭喜你掌握了 Plop 的核心动作!下一篇我们会学习模板语法,理解 Handlebars 在 Plop 中的具体用法。