Plop Documentation
repository·main·Indexed 27 days ago
https://github.com/plopjs/plopA micro-generator framework for automating the creation of code files and text-based assets. Plop combines Inquirer.js for interactive prompts and Handlebars.js for templating. It provides a CLI for executing generators and a programmatic API via node-plop for integrating code generation logic directly into Node.js applications, including support for custom actions, prompts, helpers, and partials.
What's inside Plop
- You can install Plop as a development dependency in your project or install it globally.
Create a plopfile.js
mainA
plopfile.jsis a Node module that exports a function receiving aplopobject. This object provides the API to define generators.Module Formats:
- CommonJS: Use
module.exports = function (plop) { ... }in.jsfiles (defaultpackage.jsontype). - ESM: Use
export default function (plop) { ... }in.jsfiles with"type": "module"inpackage.json, or in.mjsfiles.
- CommonJS: Use
Use Node-Plop to automate code generation in Node.js
mainUse
node-plopto integrate Plop's code generation logic directly into your Node.js applications or automation scripts without using the CLI. This allows you to trigger generators programmatically, making it easier to automate workflows or test generator logic within a test suite.import nodePlop from "node-plop"; // Load an instance of plop from a plopfile const plop = await nodePlop(`./path/to/plopfile.js`); // Get a generator by name const basicAdd = plop.getGenerator("basic-add"); // Run all the generator actions using the data specified basicAdd.runActions({ name: "this is a test" }).then(function (results) { // do something after the actions have run });Wrap Plop to create a custom CLI
mainYou can wrap
plopto build your own custom CLI tool. This requires aplopfile.js, apackage.json, and your template files. UsePlop.launchto initialize the environment andrunto execute the generators.Note: If you use the
(env) => run(env, undefined, true)pattern, you can pass generator arguments directly without using the--separator. If you prefer the standard Plop behavior (requiring--before generator arguments), usePlop.launch({}, run)instead.#!/usr/bin/env node const path = require("path"); const args = process.argv.slice(2); const { Plop, run } = require("plop"); const argv = require("minimist")(args); Plop.launch( { cwd: argv.cwd, // Use __dirname to ensure plopfile.js is always found regardless of CWD configPath: path.join(__dirname, "plopfile.js"), require: argv.require, completion: argv.completion, // This merges plop argv and generator argv, removing the need for '--' }, (env) => run(env, undefined, true), );Configure action settings with ActionConfig
mainEvery action in the
actionsarray uses anActionConfigobject.ActionConfig Interface:
type(String): The type of action (e.g.,add,modify,addMany, or a custom type created viasetActionType).force(Boolean, default:false): Force the action to execute (behavior varies by action type).data(Object | Function): Data to be merged with user input. Can be a function returning an object or a Promise resolving to an object.abortOnFail(Boolean, default:true): Iftrue, subsequent actions are cancelled if this action fails.skip(Function, optional): A function that returns a string reason if the action should be skipped.
Create dynamic actions based on prompt answers
mainThe
actionsproperty inGeneratorConfigcan be a function that receivesanswersas an argument. This allows you to return different sets of actions based on user input.module.exports = function (plop) { plop.setGenerator("test", { prompts: [ { type: "confirm", name: "wantTacos", message: "Do you want tacos?", }, ], actions: function (data) { var actions = []; if (data.wantTacos) { actions.push({ type: "add", path: "folder/{{dashCase name}}.txt", templateFile: "templates/tacos.txt", }); } else { actions.push({ type: "add", path: "folder/{{dashCase name}}.txt", templateFile: "templates/burritos.txt", }); } return actions; }, }); };Configure package.json for a custom Plop CLI
mainWhen packaging Plop as a CLI tool, your
package.jsonshould define the entry point in thebinfield and includeplopas a dependency.{ "name": "create-your-name-app", "version": "1.0.0", "main": "index.js", "scripts": { "start": "plop" }, "bin": { "create-your-name-app": "./index.js" }, "preferGlobal": true, "dependencies": { "plop": "^2.6.0" } }Configure a generator with setGenerator
mainUse
plop.setGenerator(name, config)to define a generator. Theconfigobject (of typeGeneratorConfig) must includepromptsandactions.GeneratorConfig Interface:
description(String, optional): A short description of the generator.prompts(Array<InquirerQuestion>): An array of questions to ask the user.actions(Array<ActionConfig>): An array of operations to perform.
Use the `addMany` action to add multiple files
mainTheaddManyaction allows you to add multiple files within a single action. Usedestinationto specify the target folder andtemplateFiles(a glob pattern) to match the templates to be added. You can use Handlebars syntax intemplateFilesto generate specific filenames, such as{{ dashCase name }}.spec.js.Implement the `bypass` method for custom Inquirer plugins
mainTo allow a third-party Inquirer plugin to support direct parameter passing in Plop, export a
bypassmethod on the plugin constructor. Thebypassmethod receivesrawValue(the user input) andpromptConfig(the prompt settings). The value returned bybypassis what gets saved into the Plopdataobject.// My confirmation inquirer plugin module.exports = MyConfirmPluginConstructor; function MyConfirmPluginConstructor() { // ...your main plugin code this.bypass = (rawValue, promptConfig) => { const lowerVal = rawValue.toString().toLowerCase(); const trueValues = ["t", "true", "y", "yes"]; const falseValues = ["f", "false", "n", "no"]; if (trueValues.includes(lowerVal)) return true; if (falseValues.includes(lowerVal)) return false; throw Error(`"${rawValue}" is not a valid ${promptConfig.type} value`); }; return this; }Use `plop.load` to import external generators and assets
mainUse
plop.loadto import generators,actionTypes,helpers, andpartialsfrom other local plopfiles or from NPM packages (viaplop-pack).Important for ES6 Modules: If you are using ES6 modules,
plop.loadis asynchronous and must be called within anasyncfunction usingawaitto ensure assets are loaded before use.Set a custom destination path in a Plop wrapper
mainWhen wrapping Plop, you may want the destination path (
dest) to be relative to the current working directory (CWD) of the user calling your CLI. You can achieve this by overriding thedestproperty in theenvobject within thePlop.launchcallback.Plop.launch( { // config like above }, (env) => { const options = { ...env, dest: process.cwd(), // makes the destination path based on the CWD when calling the wrapper }; return run(options, undefined, true); }, );