Plop 简介
实战:用 Plop 批量生成 Vue 组件
通过一个完整的 Vue 组件生成案例,把 prompts、actions、模板语法和 helpers 串联起来。
🎯 引言
学完这篇文章,你将通过一个完整的实战案例,把前面学到的 Plop 知识串起来。我们会实现一个“Vue 组件生成器”,它可以根据你的选择,自动生成组件文件、样式文件和测试文件。
🧱 实战目标
我们要实现一个生成器,运行后能够:
- 询问组件名称。
- 询问是否需要
<script setup>。 - 询问是否需要样式文件。
- 询问是否需要测试文件。
- 根据回答生成对应的文件。
✨ 项目结构
完成后的项目结构如下:
plop-demo/
├── plopfile.mjs
├── plop-templates/
│ ├── component.hbs
│ ├── component.scss.hbs
│ └── component.test.hbs
└── src/
├── components/
└── components/__tests__/
🚀 第一步:编写 plopfile.mjs
plopfile.mjs
export default function (plop) {
plop.setHelper('now', function () {
const date = new Date();
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
});
plop.setGenerator('vue-component', {
description: '创建一个完整的 Vue 组件',
prompts: [
{
type: 'input',
name: 'name',
message: '请输入组件名称(英文大驼峰)',
validate: function (value) {
if (value.trim() === '') {
return '组件名称不能为空';
}
if (!/^[A-Z][a-zA-Z0-9]*$/.test(value)) {
return '组件名称必须以英文大写字母开头';
}
return true;
}
},
{
type: 'confirm',
name: 'useSetup',
message: '是否使用 <script setup> 语法?',
default: true
},
{
type: 'confirm',
name: 'hasStyle',
message: '是否需要生成样式文件?',
default: true
},
{
type: 'confirm',
name: 'hasTest',
message: '是否需要生成测试文件?',
default: false
}
],
actions: [
{
type: 'add',
path: 'src/components/{{pascalCase name}}.vue',
templateFile: 'plop-templates/component.hbs'
},
{
type: 'add',
path: 'src/components/__tests__/{{pascalCase name}}.test.js',
templateFile: 'plop-templates/component.test.hbs',
skip: function (answers) {
if (!answers.hasTest) {
return '跳过测试文件生成';
}
}
},
{
type: 'add',
path: 'src/components/{{pascalCase name}}.scss',
templateFile: 'plop-templates/component.scss.hbs',
skip: function (answers) {
if (!answers.hasStyle) {
return '跳过样式文件生成';
}
}
}
]
});
}
🛠 第二步:编写模板文件
组件模板
plop-templates/component.hbs
<!--
组件:{{pascalCase name}}
创建日期:{{now}}
-->
<template>
<div class="{{kebabCase name}}">
{{pascalCase name}} 组件
</div>
</template>
{{#if useSetup}}
<script setup>
// {{pascalCase name}} 组件逻辑
</script>
{{else}}
<script>
export default {
name: '{{pascalCase name}}'
};
</script>
{{/if}}
{{#if hasStyle}}
<style scoped>
@import './{{pascalCase name}}.scss';
</style>
{{/if}}
样式模板
plop-templates/component.scss.hbs
.{{kebabCase name}} {
/* {{pascalCase name}} 组件样式 */
}
测试模板
plop-templates/component.test.hbs
import { describe, it, expect } from 'vitest';
import { mount } from '@vue/test-utils';
import {{pascalCase name}} from '../{{pascalCase name}}.vue';
describe('{{pascalCase name}}', () => {
it('渲染成功', () => {
const wrapper = mount({{pascalCase name}});
expect(wrapper.exists()).toBe(true);
});
});
💡 第三步:运行生成器
执行命令:
npx plop vue-component
按提示输入:
? 请输入组件名称(英文大驼峰) UserInfo
? 是否使用 <script setup> 语法? Yes
? 是否需要生成样式文件? Yes
? 是否需要生成测试文件? Yes
运行完成后,会生成以下文件:
src/components/
├── UserInfo.vue
├── UserInfo.scss
└── __tests__/
└── UserInfo.test.js
⚡ 第四步:查看生成的组件
src/components/UserInfo.vue
<!--
组件:UserInfo
创建日期:2026-07-16
-->
<template>
<div class="user-info">
UserInfo 组件
</div>
</template>
<script setup>
// UserInfo 组件逻辑
</script>
<style scoped>
@import './UserInfo.scss';
</style>
注意
<style> 里用了 @import './UserInfo.scss',这样样式文件和组件文件可以分开维护。如果你希望样式直接内联,也可以把 SCSS 内容写进组件模板里。🧾 小节总结
- 实战案例综合运用了
prompts、actions、模板语法和自定义 helper。 - 通过
confirm类型的问题,可以控制是否生成可选文件。 - 使用
skip函数可以跳过不需要的动作,保持输出简洁。 - 自定义
nowhelper 可以在生成的文件中加入创建日期。
❓ 知识问答
Q1:为什么把测试文件放在 __tests__ 目录下?
A:这是前端项目常见的测试文件组织方式,便于测试工具统一发现和收集测试用例。
Q2:如果用户选择不需要样式,为什么组件模板里还要写 {{#if hasStyle}}?
A:因为 skip 只控制是否生成 .scss 文件,组件模板里 <style> 块是否出现由 hasStyle 决定。两者配合使用,才能保持生成结果一致。
Q3:<script setup> 和传统 <script> 写法有什么区别?
A:<script setup> 是 Vue 3 的语法糖,代码更简洁。如果项目使用 Vue 2,应该选择传统写法。
Q4:这个生成器可以直接用到真实项目里吗?
A:可以作为基础版本。真实项目中,你可能还需要根据团队的目录规范、测试框架、样式方案做进一步调整。
🧪 小练习
请在实战案例的基础上,增加一个新功能:
当组件名称输入 UserCard 时,自动生成一个 props 定义,包含 title 和 desc 两个属性。
提示:可以在 prompts 中增加一个 confirm 问题,在模板中用 {{#if}} 判断。
{{#if hasProps}}
<script setup>
const props = defineProps({
title: String,
desc: String
});
</script>
{{/if}}
🎉 恭喜你已经完成了 Plop 课程的学习!现在你可以在自己的项目里用 Plop 自动生成常用文件,大幅提升开发效率。
