{
    "componentChunkName": "component---src-components-blog-post-jsx",
    "path": "/blog/2020-01-29-automating-file-creation-with-javascript/",
    "result": {"data":{"site":{"siteMetadata":{"author":"Monica Powell","siteUrl":"https://www.aboutmonica.com"}},"mdx":{"id":"5ddf86ab-341b-5603-874c-97c8d3ade985","timeToRead":6,"body":"var _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"title\": \"Automating File Creation With JavaScript\",\n  \"date\": \"2020-01-29T12:40:44.608Z\",\n  \"template\": \"post\",\n  \"slug\": \"2020-01-29-automating-file-creation-with-javascript\",\n  \"tags\": [\"JavaScript\", \"Tutorial\"],\n  \"category\": [\"tutorial\"],\n  \"featured\": true,\n  \"description\": \"This article walks through how to use plop a micro-generator to generate new text-based files.\"\n};\n\nvar makeShortcode = function makeShortcode(name) {\n  return function MDXDefaultShortcode(props) {\n    console.warn(\"Component \" + name + \" was not imported, exported, or provided by MDXProvider as global scope\");\n    return mdx(\"div\", props);\n  };\n};\n\nvar TableOfContents = makeShortcode(\"TableOfContents\");\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(TableOfContents, {\n    headings: props.tableOfContents,\n    mdxType: \"TableOfContents\"\n  }), mdx(\"p\", null, \"Do you ever find yourself copying and pasting the same boilerplate code for multiple files at a time? Do you stop and think every time you have to construct an \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.iso.org/iso-8601-date-and-time-format.html\"\n  }, \"ISO 8601\"), \" formatted date? \\uD83E\\uDD14\\nHow frustrating would it be if you could no longer copy and paste your template code from one file to another?\"), mdx(\"p\", null, \"This article will walk through how to quickly create a command-line interface (CLI) tool that generates text-based files. In particular, the examples in this article will walk through how to create templates to generate a new \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".jsx\"), \" Page in a \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.gatsbyjs.org/\"\n  }, \"Gatsby\"), \" blog with tests as well as how to generate markdown files with the initial structure of a blog post. These examples should serve as inspiration as the sky is the limit in regards to what type of text files can be generated based on the needs of a particular developer or project.\"), mdx(\"p\", null, mdx(\"img\", {\n    parentName: \"p\",\n    \"src\": \"/media/plop-recording.gif\",\n    \"alt\": \"gif of the final CLI created by this tutorial\"\n  })), mdx(\"h2\", {\n    \"id\": \"why-scaffolding\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h2\",\n    \"href\": \"#why-scaffolding\",\n    \"aria-label\": \"why scaffolding permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Why Scaffolding?\"), mdx(\"p\", null, \"The CLI we will be creating is a type of scaffolding software as it generates starter code based on templates. Note that starter code generated by scaffolding generally is not ready for production however it still has benefits as it can improve the developer experience, make it easier to implement standardization and enable faster software delivery.\"), mdx(\"p\", null, \"Some of the benefits of scaffolding can be:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"involving less work - no more copying and pasting boilerplate code (i.e., relative imports from one file to another)\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"automating the implementation of design patterns and best practices\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"reducing time to generate new projects or components\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"being less error-prone than the manual process of copy & pasting & editing\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"encouraging consistency and implementation of design patterns\")), mdx(\"p\", null, \"Scaffolding can answer questions like:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Where should translations for this React component live?\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Where can I find our current code standards?\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"What directory should this type of file live in?\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Should I use cameCase? snake_case? kebab-case? PascalCase? UPPERCASE_SNAKE_CASE?\")), mdx(\"h2\", {\n    \"id\": \"is-scaffolding-worth-it\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h2\",\n    \"href\": \"#is-scaffolding-worth-it\",\n    \"aria-label\": \"is scaffolding worth it permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Is scaffolding \\\"worth it\\\"?\"), mdx(\"p\", null, \"Implementing scaffolding takes time. The potential benefits of scaffolding a particular piece of software versus time involved in developing it should be assessed to determine if it's worth the time and effort to implement scaffolding. If we are analyzing the estimated time invested vs. saved and not other intangible benefits like consistency or reducing context switching you can use the \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://xkcd.com/1205/\"\n  }, \"below XKCD comic\"), \" to assess if it's worth implementing.\"), mdx(\"p\", null, mdx(\"img\", {\n    parentName: \"p\",\n    \"src\": \"/media/is_it_worth_the_time.png\",\n    \"alt\": \"is it worth the time comic\"\n  })), mdx(\"p\", null, mdx(\"em\", {\n    parentName: \"p\"\n  }, \"xkcd Is It Worth the Time?\")), mdx(\"p\", null, \"In terms of other potential down-sides, code requirements often evolve over time and scaffolded templates may require future maintenance as new requirements surface. Ideally refactoring the scaffolding template should feel like a natural extension of a workflow versus like maintenance is additional overhead and slowing down the process. Some implementation details or decisions can be concealed by scaffolding which can reduce context depending on the tool the actual logic being used to generate files can be easily accessible.\"), mdx(\"h2\", {\n    \"id\": \"micro-generator-tool-plopjs\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h2\",\n    \"href\": \"#micro-generator-tool-plopjs\",\n    \"aria-label\": \"micro generator tool plopjs permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Micro-generator tool: PlopJS\"), mdx(\"p\", null, \"If you\\u2019re looking for a lightweight way to introduce scaffolding into your workflow consider using \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/plopjs/plop\"\n  }, \"Plop\"), \", a micro-generator. Plop allows developers to generate files based on user input via a Command Line Interface (CLI) with minimal setup.\"), mdx(\"h3\", {\n    \"id\": \"how-does-plop-work\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h3\",\n    \"href\": \"#how-does-plop-work\",\n    \"aria-label\": \"how does plop work permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"How does Plop work?\"), mdx(\"p\", null, \"PlopJS combines the Handlebars templating language and \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/SBoudrias/Inquirer.js/\"\n  }, \"Inquirer.js\"), \". Inquirer.js is a tool for collecting user input via CLI. You can present questions a.k.a CLI prompts in different formats with inquirer. \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://handlebarsjs.com/\"\n  }, \"Handlebars\"), \" is a templating language that you may be familiar with. Templating languages are used in a variety of contexts from displaying React props, creating e-mail templates, or even making your workflow easier as we'll see today. Before, I was using \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".jsx\"), \" in React I worked with the \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://shopify.github.io/liquid/\"\n  }, \"Liquid\"), \" templating language in \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://jekyllrb.com/\"\n  }, \"Jekyll\"), \" and Handlebars in \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://foundation.zurb.com/emails.html\"\n  }, \"Foundation for Emails\"), \".\"), mdx(\"p\", null, \"By combining the functionality of Inquirer.js with Handlebars, plop allows users to quickly create templates with minimal setup. If you're not familiar with software templates you can think of them as similar to mail merge in a word processor. In mail merge, there's generally a spreadsheet with data which is and then merged with a template document that has placeholder variables. When the data and template are combined with mail merge the result is a version of the document that contains data in the proper places (as determined by the placeholder variables). The data in that file is populated during the mail merge process and customized as appropriate for the recipient. In our case, the data entered in the CLI will be populated into the template and generate a new file when we run \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"plop\"), \".\"), mdx(\"h3\", {\n    \"id\": \"plop-set-up\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h3\",\n    \"href\": \"#plop-set-up\",\n    \"aria-label\": \"plop set up permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Plop Set Up\"), mdx(\"p\", null, \"If you already have a directory with a \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"package.json\"), \" where you want to generate files then Plop can be installed with \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"yarn\"), \" with the following command:\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"yarn add -D plop\\n\")), mdx(\"p\", null, \"or \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"npm\"), \" using:\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \" npm install \\u2014save-dev plop\\n\")), mdx(\"p\", null, \"If you don't already have a \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"package.json\"), \" you can create one by typing \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"yarn init\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"npm init\"), \" and walking through the steps and then installing \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"plop\"), \".\"), mdx(\"p\", null, \"Once \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"plop\"), \" is installed as a package dependency we should update the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"scripts\"), \" in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"package.json\"), \" file to enable us to run \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"yarn plop\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"npm plop\"), \" to run \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"plop\"), \". You can name \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"\\\"plop\\\"\"), \" whatever you want the command to be for example \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"\\\"generate\\\": \\\"plop\\\"\"), \" and it will behave the same way.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-json\"\n  }, \"\\\"scripts\\\": {\\n \\\"plop\\\": \\\"plop\\\"\\n}\\n\")), mdx(\"p\", null, \"Unlike code snippets, plop doesn\\u2019t require additional setup to share between computers or across developers and lives in version control. Also, plop allows multiple files to be generated at once.\"), mdx(\"p\", null, \"Now we can create our first \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"plopfile.js\"), \" in the root level of our directory which is where the plop magic will happen.\"), mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"plopfile.js\"), \":\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-js\"\n  }, \"module.exports = function(plop) {\\n  /* welcome messag that will display in CLI */\\n  plop.setWelcomeMessage(\\n    \\\"Welcome to plop! What type of file would you like to generate?\\\"\\n  ),\\n    /* name and description of our template */\\n    plop.setGenerator(\\\"generate blog post \\u270F\\uFE0F\\\", {\\n      description: \\\"Template for generating blog posts\\\",\\n\\n      prompts: [\\n        /* inquirer prompts */\\n        /* questions we want to ask in CLI and save questions for*/\\n      ],\\n\\n      actions: [\\n        /* what should be generated based off of the above prompts */\\n      ],\\n    })\\n}\\n\")), mdx(\"p\", null, \"Now that we have a baseline \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"plopfile.js\"), \" let's add some functionality. First we will add the ability to generate the frontmatter or metadata that needs to appear on every draft blog post in order for Gatsby to properly generate it.\"), mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"sample frontmatter\"), \":\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-markdown\"\n  }, \"---\\ntitle: Automating File Creation With JavaScript\\ndate: 2020-01-14T12:40:44.608Z\\ntemplate: \\\"post\\\"\\ndraft: true\\nslug: 2020-01-14-automating-file-creation-with-javascript\\ncategory:\\n  - tutorial\\ndescription: This article walks through how to use plop a micro-generator to generate new text-based files.\\n---\\n\")), mdx(\"p\", null, \"We should update the plop file to add built-in functionality to format today's date into an ISOString and use Inquirer (built into Plop) to create CLI prompts and collect input.\\nWe will use \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"new Date(Date.now())\"), \" to get the current date. We will format the date both as an \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ISOStringDate\"), \": \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"2020-01-14T12:40:44.608Z\"), \" and as a \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"shortDate\"), \": \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"2020-01-14\"), \". The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ISOStringDate\"), \"\\nwill be used in the frontmatter whereas the\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"shortDate\"), \"will be used in the file path of the newly generated file. The date utils will be returned byset\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"plop.setHelper()\"), \"in order to expose the values in our\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".hbs\"), \"templates by writing\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"{{ISOStringDate}}\"), \"or\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"{{shortDate}}\"), \".\"), mdx(\"p\", null, \"In terms of collecting input in prompts the basic structure of a prompt is\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-javascript\"\n  }, \"{\\n  // example inquirer types:\\n  // input, list, raw list, expandable list, checkbox, password, editor\\n  // learn more here: https://github.com/SBoudrias/Inquirer.js#prompt-types\\n  type: \\\"input\\\",\\n\\n  name: \\\"description\\\",\\n\\n  message: \\\"Description of post:\\\",\\n\\n  }\\n\")), mdx(\"p\", null, \"The most complex prompt in this example is this list prompt which allows users to use arrow keys to select the category for their blog post and then we transform that value to a lowercase string. The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"filter\"), \" prompt can be used to convert a user-friendly value like \\\"yellow\\\" to being inserted in the template as \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"#ffff00\"), \".\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-javascript\"\n  }, \" {\\n          type: \\\"list\\\",\\n          name: \\\"category\\\",\\n          message: \\\"Category:\\\",\\n          choices: [\\\"Tutorial\\\", \\\"Reflection\\\"],\\n          filter: function(val) {\\n            return val.toLowerCase()\\n          },\\n        },\\n\")), mdx(\"p\", null, \"Once all of the prompts are squared away we need to do something with the input by adding an action:\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-javascript\"\n  }, \"{\\n          type: \\\"add\\\",\\n          path: `content/blog/${shortDate}-{{dashCase title}}.md`,\\n          templateFile: \\\"src/plop-templates/blog-post.hbs\\\",\\n        },\\n\")), mdx(\"p\", null, \"A type of action \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"add\"), \" creates a new file at the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"path\"), \" and interpolates the responses from the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"prompts\"), \" and values from plop helpers into the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"templateFile\"), \".\"), mdx(\"p\", null, \"The complete \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"plopfile.js\"), \" at this point should look something like this:\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-js\",\n    \"metastring\": \"{2-5,12-41}\",\n    \"{2-5,12-41}\": true\n  }, \"module.exports = function(plop) {\\n  const today = new Date(Date.now())\\n  const shortDate = today.toISOString().split(\\\"T\\\")[0]\\n  plop.setHelper(\\\"shortDate\\\", () => shortDate),\\n    plop.setHelper(\\\"ISOStringDate\\\", () => today.toISOString()),\\n    // optional welcome message\\n\\n    plop.setWelcomeMessage(\\n      \\\"Welcome to plop! What type of file would you like to generate?\\\"\\n    ),\\n    plop.setGenerator(\\\"blog post \\u270F\\uFE0F\\\", {\\n      description: \\\"template for generating blog posts\\\",\\n      prompts: [\\n        {\\n          type: \\\"input\\\",\\n          name: \\\"title\\\",\\n          message: \\\"Title of post:\\\",\\n        },\\n        {\\n          type: \\\"input\\\",\\n          name: \\\"description\\\",\\n          message: \\\"Description of post:\\\",\\n        },\\n\\n        {\\n          type: \\\"list\\\",\\n          name: \\\"category\\\",\\n          message: \\\"Category:\\\",\\n          choices: [\\\"Tutorial\\\", \\\"Reflection\\\"],\\n          filter: function(val) {\\n            return val.toLowerCase()\\n          },\\n        },\\n      ],\\n      actions: [\\n        {\\n          type: \\\"add\\\",\\n          path: `content/blog/${shortDate}-{{dashCase title}}.md`,\\n          templateFile: \\\"src/plop-templates/blog-post.hbs\\\",\\n        },\\n      ],\\n    })\\n}\\n\")), mdx(\"p\", null, \"In order to actually use this we need to create the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"blog-post.hbs\"), \" template in our \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"src/plop-templates/\"), \" directory. This \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".hbs\"), \" file is where we parametrize the code to only keep the bits that we need from file to file and to have placeholders for things that change based on the name or type of thing that is being generated. Plop has built-in case helpers like \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"titleCase\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"dashCase\"), \" to format input (view the built-in case modifiers at: \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://plopjs.com/documentation/#case-modifiers\"\n  }, \"https://plopjs.com/documentation/#case-modifiers\"), \")\"), mdx(\"p\", null, \"blog-post.hbs\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-handlebars\"\n  }, \"---\\n\\ntitle: {{titleCase title}} # from title prompt\\n\\ndate: {{ISOStringDate}} # from plopHelper\\n\\ntemplate: \\u201Cpost\\u201D\\n\\ndraft: true\\n\\nslug: {{shortDate}}-{{dashCase title}} # from plop helper and title prompt\\n\\ncategory:\\n\\n- {{category}} # from category prompt\\n\\ndescription: {{description}} # from description prompt\\n\\n---\\n## Intro\\n{{description}}\\n<!\\u2014 The blog post starts here \\u2014>\\n\")), mdx(\"p\", null, \"Running \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"yarn plop\"), \" now should walk you through the prompts we added and generate a new file based off of the responses to the prompts and the handlebars template. The file that was generated will\\nbe at \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"content/blog/${shortDate}-{{dashCase title}}.md\"), \" (or wherever you set the path in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"action\"), \").\"), mdx(\"h3\", {\n    \"id\": \"plop-example-to-generate-jsx-page\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h3\",\n    \"href\": \"#plop-example-to-generate-jsx-page\",\n    \"aria-label\": \"plop example to generate jsx page permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Plop Example to Generate JSX Page\"), mdx(\"p\", null, \"Below is an update plopfile and example handlebars template for generating a \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Page.jsx\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Page.test.jsx\"), \":\"), mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Page.hbs\"), \":\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-handlebars\"\n  }, \"import React from \\\"react\\\"\\n\\n\\n\\n// Components\\n\\nimport { Helmet } from \\\"react-helmet\\\"\\n\\nimport { graphql } from \\\"gatsby\\\"\\n\\nimport Layout from \\\"../components/page/layout\\\"\\n\\n\\n\\nconst {{properCase pageName}} = ({\\n\\ndata: {\\n\\nsite: {\\n\\nsiteMetadata: { title },\\n\\n},\\n\\n},}) => (<Layout>\\n\\n<div>\\n\\n<Helmet title={title} />\\n\\n</div>\\n\\n</Layout>)\\n\\n\\n\\n\\n\\nexport default {{properCase pageName}}\\n\\n\\n\\nexport const pageQuery = graphql`\\n\\nquery {\\n\\nsite {\\n\\nsiteMetadata {\\n\\ntitle\\n\\n}\\n\\n}\\n\\n}\\n\")), mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"pageTest.hbs\"), \":\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-handlebars\"\n  }, \"import React from \\\"react\\\"\\n\\nimport { shallow } from \\\"enzyme\\\"\\n\\nimport Layout from \\\"../components/page/layout\\\"\\n\\nimport {{properCase pageName}} from \\\"./{{properCase pageName}}\\\"\\n\\nimport { Helmet } from \\\"react-helmet\\\"\\n\\n\\n\\nconst data = {\\n\\nsite: {\\n\\nsiteMetadata: {\\n\\ntitle: \\u201Cmonica*dev\\u201D,\\n\\n},\\n\\n}\\n\\n}\\n\\n\\n\\ndescribe(\\u201C{{properCase pageName}}\\u201D, () => {\\n\\nconst component = shallow(\\n\\n<{{properCase pageName}} data={data} />)\\n\\n\\n\\nit(\\u201Crenders page layout\\u201D, () => {\\n\\nexpect(component.find(Layout)).toHaveLength(1)\\n\\n})\\n\\n\\n\\nit(\\u201Crenders helmet with site title from site metadata\\u201D, () => {\\n\\nexpect(component.find(Helmet).props().title).toBe(\\u201Cmonica*dev\\u201D)\\n\\n})\\n\\n})\\n\")), mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"plopfile.js\")), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-js\"\n  }, \"module.exports = function(plop) {\\n\\nconst today = new Date(Date.now())\\n\\nconst shortDate = today.toISOString().split(\\\"T\\\")[0]\\n\\nplop.setHelper(\\\"shortDate\\\", () => shortDate),\\n\\nplop.setHelper(\\\"ISOStringDate\\\", () => today.toISOString()),\\n\\nplop.setGenerator(\\\"generate blog post \\u270F\\uFE0F\\\", {\\n\\n /*...*/\\n\\n}),\\n\\nplop.setGenerator(\\\"Create new page \\uD83D\\uDCC3\\\", {\\n\\ndescription: \\\"template for creating a new page\\\",\\n\\nprompts: [\\n\\n{\\n\\ntype: \\\"input\\\",\\n\\nname: \\\"pageName\\\",\\n\\nmessage: \\\"Page name:\\\",\\n\\n},\\n\\n],\\n\\nactions: [\\n\\n{\\n\\ntype: \\u201Cadd\\u201D,\\n\\npath: \\u201Csrc/pages/{{properCase pageName}}.jsx\\u201D,\\n\\ntemplateFile: \\u201Csrc/plop-templates/page.hbs\\u201D,\\n\\n},\\n\\n{\\n\\ntype: \\u201Cadd\\u201D,\\n\\npath: \\u201Csrc/pages/{{camelCase pageName}}.test.jsx\\u201D,\\n\\ntemplateFile: \\u201Csrc/plop-templates/pageTest.hbs\\u201D,\\n\\n},\\n\\n],\\n\\n})\\n\\n}\\n\")), mdx(\"h2\", {\n    \"id\": \"formatting-output\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h2\",\n    \"href\": \"#formatting-output\",\n    \"aria-label\": \"formatting output permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Formatting Output\"), mdx(\"p\", null, \"I ran into an issue where because the initial template files were \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".hbs\"), \" files the generated files weren't necessarily formatted like \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".md\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".jsx\"), \". I already had prettier set up in my project so in order to solve the formatting issues I ended up updating my \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"plop\"), \" script shorthand to do format all files after running plop. However, this should be refactored to only format the relevant, just generated files.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-json\"\n  }, \"\\\"scripts\\\": {\\n  ...\\n  \\\"format\\\": \\\"prettier \\u2014write \\\\\\\"**/*.{js,jsx,json,md}\\\\\\\"\\\",\\n  \\\"plop\\\": \\u201Cplop && yarn format\\u201D\\n}\\n\")), mdx(\"h2\", {\n    \"id\": \"conclusion\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h2\",\n    \"href\": \"#conclusion\",\n    \"aria-label\": \"conclusion permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Conclusion\"), mdx(\"p\", null, \"As a recap, we used \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"plop\"), \" to generate boilerplate code that is shared across certain types of files. Ideally implementing some type of automation for file creation should reduce time to create functional files, be less error-prone than copy + pasting + editing, encourages consistency and implementation of design patterns.\"), mdx(\"h3\", {\n    \"id\": \"create-your-own-template\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h3\",\n    \"href\": \"#create-your-own-template\",\n    \"aria-label\": \"create your own template permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Create Your Own Template\"), mdx(\"p\", null, \"Some ideas for things to incorporate in templates:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Create different templates based on the type of React component (examples in React-Boilerplate's generators)\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Generate comments or base-level documentation\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Generate self-contained directories or packages with, index file (and related tests), package.json and README.md\")), mdx(\"h3\", {\n    \"id\": \"additional-resources\",\n    \"style\": {\n      \"position\": \"relative\"\n    }\n  }, mdx(\"a\", {\n    parentName: \"h3\",\n    \"href\": \"#additional-resources\",\n    \"aria-label\": \"additional resources permalink\",\n    \"className\": \"anchor before\"\n  }, mdx(\"svg\", {\n    parentName: \"a\",\n    \"aria-hidden\": \"true\",\n    \"focusable\": \"false\",\n    \"height\": \"16\",\n    \"version\": \"1.1\",\n    \"viewBox\": \"0 0 16 16\",\n    \"width\": \"16\"\n  }, mdx(\"path\", {\n    parentName: \"svg\",\n    \"fillRule\": \"evenodd\",\n    \"d\": \"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"\n  }))), \"Additional Resources\"), mdx(\"p\", null, \"Last year, I had the opportunity to streamline the creation of new packages via CLI prompts (which inspired \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://noti.st/monica/AjCX04/automate-react-workflow\"\n  }, \"my talk on generating React components\"), \" at React Girls Conf in London) and led me to learn more about Plop. If you're interested in learning more about Plop in a React context or alternatives to Plop check out my previous talk.\"), mdx(\"p\", null, mdx(\"img\", {\n    parentName: \"p\",\n    \"src\": \"/media/automate-react-workflow-sketchnotes.jpg#center\",\n    \"alt\": \"Sketchnotes from Monica's Automating React Workflow Talk at React Girls Conf in London\"\n  }), \"\\n\", mdx(\"em\", {\n    parentName: \"p\"\n  }, \"Sketchnotes by \", mdx(\"a\", {\n    parentName: \"em\",\n    \"href\": \"https://twitter.com/malweene\"\n  }, \"@malweene\"), \" from my talk at React Girls Conf\")), mdx(\"p\", null, \"Here are some additional resources that may be helpful as you are getting more familiar with generating files with Plop.\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://github.com/plopjs/plop\"\n  }, \"https://github.com/plopjs/plop\")), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://github.com/react-boilerplate/react-boilerplate/tree/master/internals/generators\"\n  }, \"https://github.com/react-boilerplate/react-boilerplate/tree/master/internals/generators\")), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://github.com/SBoudrias/Inquirer.js/\"\n  }, \"https://github.com/SBoudrias/Inquirer.js/\")), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://handlebarsjs.com/\"\n  }, \"https://handlebarsjs.com/\")), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://prettier.io/\"\n  }, \"https://prettier.io/\")), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://github.com/M0nica/generate-kawaii-components\"\n  }, \"https://github.com/M0nica/generate-kawaii-components\"))));\n}\n;\nMDXContent.isMDXComponent = true;","tableOfContents":{"items":[{"url":"#why-scaffolding","title":"Why Scaffolding?"},{"url":"#is-scaffolding-worth-it","title":"Is scaffolding \"worth it\"?"},{"url":"#micro-generator-tool-plopjs","title":"Micro-generator tool: PlopJS","items":[{"url":"#how-does-plop-work","title":"How does Plop work?"},{"url":"#plop-set-up","title":"Plop Set Up"},{"url":"#plop-example-to-generate-jsx-page","title":"Plop Example to Generate JSX Page"}]},{"url":"#formatting-output","title":"Formatting Output"},{"url":"#conclusion","title":"Conclusion","items":[{"url":"#create-your-own-template","title":"Create Your Own Template"},{"url":"#additional-resources","title":"Additional Resources"}]}]},"frontmatter":{"title":"Automating File Creation With JavaScript","date":"January 29, 2020","description":"This article walks through how to use plop a micro-generator to generate new text-based files.","tags":["JavaScript","Tutorial"]}},"allWebMentionEntry":{"edges":[{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/repost/twitter/waterproofheart/1280928016076615681/1281241089605808132","wmProperty":"repost-of","wmId":822191,"type":"entry","url":"https://twitter.com/GatsbyJS/status/1281241089605808132","likeOf":null,"author":{"url":"https://twitter.com/GatsbyJS","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/285a21ea01d699be05f11cc16e836f499cce1202b3a48d6fad26f636040c4dc3.png","name":"Gatsby"},"published":"July 09, 2020","content":{"text":"Thanks @GirlsCodeMK for having me! The recording from today's stream is available here: twitch.tv/videos/6736717… and here's the blog post I r"}}},{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/like/twitter/waterproofheart/1280928016076615681/1009594769817796608","wmProperty":"like-of","wmId":821685,"type":"entry","url":"https://twitter.com/waterproofheart/status/1280928016076615681#favorited-by-1009594769817796608","likeOf":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","author":{"url":"https://twitter.com/kefimochi","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/108466a324a4e848226cc58a305b730a5a47674c6b609d399611c06c283b1913.jpg","name":"Kate 💫 BLM"},"published":null,"content":null}},{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/like/twitter/waterproofheart/1280928016076615681/453227243","wmProperty":"like-of","wmId":821686,"type":"entry","url":"https://twitter.com/waterproofheart/status/1280928016076615681#favorited-by-453227243","likeOf":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","author":{"url":"https://twitter.com/JakeHerp","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/ca60b01838aa1b4a984641d8352b07edd7dabac5c70bb2a5d83bf2a70a7d3ef0.jpg","name":"Jacob Herper"},"published":null,"content":null}},{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/post/twitter/waterproofheart/1280930078755557377","wmProperty":"mention-of","wmId":821659,"type":"entry","url":"https://twitter.com/GirlsCodeMK/status/1280930078755557377","likeOf":null,"author":{"url":"https://twitter.com/GirlsCodeMK","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/d05068b8e10011ffed7e7bac1942cbfc758e376267b144a004a475ada80c1cf1.jpg","name":"Eva - includeJS.dev 🌈"},"published":"July 08, 2020","content":{"text":"You are a ⭐ Monica!"}}},{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/like/twitter/waterproofheart/1280928016076615681/51530847","wmProperty":"like-of","wmId":821657,"type":"entry","url":"https://twitter.com/waterproofheart/status/1280928016076615681#favorited-by-51530847","likeOf":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","author":{"url":"https://twitter.com/MDarrik","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/c9c470c3f759e894736e3fe88241d1a6ac0fca6c9c708b3dcfcf5b29410d4273.jpg","name":"Darrik Moberg"},"published":null,"content":null}},{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/like/twitter/waterproofheart/1280928016076615681/33863158","wmProperty":"like-of","wmId":821658,"type":"entry","url":"https://twitter.com/waterproofheart/status/1280928016076615681#favorited-by-33863158","likeOf":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","author":{"url":"https://twitter.com/chadtomkiss","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/083fca9f8e99a877db01f0552881112f91974e0d053f6035d7143b7863953e8d.jpg","name":"Chuck Tomkress"},"published":null,"content":null}},{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/repost/twitter/waterproofheart/1223233324820377602/1223372077668929539","wmProperty":"repost-of","wmId":786362,"type":"entry","url":"https://twitter.com/plopjs/status/1223372077668929539","likeOf":null,"author":{"url":"https://twitter.com/plopjs","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/e46e5e802f5968bac97291048d550bc3b630509e155e6b71e29f9546bc487c90.png","name":"Plop"},"published":"January 31, 2020","content":{"text":"I wrote a tutorial about mail merge for developers!  ✉️\nIt walks through using @plopjs to quickly create a CLI to automate the generation of"}}},{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/repost/twitter/waterproofheart/1223233324820377602/1223869778307080192","wmProperty":"repost-of","wmId":786361,"type":"entry","url":"https://twitter.com/javascriptd/status/1223869778307080192","likeOf":null,"author":{"url":"https://twitter.com/javascriptd","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/8926516280df06f09e9ac45cd9df37e0e2ed500388fbfd669e40b7ec4fb680df.jpeg","name":"Javascript Digest"},"published":"February 02, 2020","content":{"text":"I wrote a tutorial about mail merge for developers!  ✉️\nIt walks through using @plopjs to quickly create a CLI to automate the generation of"}}},{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/like/twitter/waterproofheart/1223233324820377602/4824581584","wmProperty":"like-of","wmId":786360,"type":"entry","url":"https://twitter.com/waterproofheart/status/1223233324820377602#favorited-by-4824581584","likeOf":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","author":{"url":"https://twitter.com/cedDevB","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/f139a0a85bef49037007ce79f78f45a228b387f77ca03b9983d34f5920966500.jpg","name":"CedDevB"},"published":null,"content":null}},{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/like/twitter/waterproofheart/1223233324820377602/2675566736","wmProperty":"like-of","wmId":786359,"type":"entry","url":"https://twitter.com/waterproofheart/status/1223233324820377602#favorited-by-2675566736","likeOf":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","author":{"url":"https://twitter.com/galenemco","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/62720561b599adab317688e0ebfa9f38aec2bd7a6205868def899b9e61595dd9.jpg","name":"Galen Corey"},"published":null,"content":null}},{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/like/twitter/waterproofheart/1223233324820377602/365550734","wmProperty":"like-of","wmId":786357,"type":"entry","url":"https://twitter.com/waterproofheart/status/1223233324820377602#favorited-by-365550734","likeOf":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","author":{"url":"https://twitter.com/haroenv","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/173147cf349e30f7f56f87c1c9a145e867c6811db43f481416198962b139ccba.jpg","name":"Haroen Viaene"},"published":null,"content":null}},{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/like/twitter/waterproofheart/1223233324820377602/16973622","wmProperty":"like-of","wmId":786358,"type":"entry","url":"https://twitter.com/waterproofheart/status/1223233324820377602#favorited-by-16973622","likeOf":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","author":{"url":"https://twitter.com/beaudaignault","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/8635c0650e457e7bd0b91b06953bdae80fe7f11bfa000c5de8e195bcf2c55763.jpg","name":"Beau Daignault"},"published":null,"content":null}},{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/like/twitter/waterproofheart/1223233324820377602/48182269","wmProperty":"like-of","wmId":786356,"type":"entry","url":"https://twitter.com/waterproofheart/status/1223233324820377602#favorited-by-48182269","likeOf":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","author":{"url":"https://twitter.com/shannon_crabill","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/9fcdedd58c12234646f620daefb5bac0dec5a6a6e97262f753f51bce4ddcabf0.jpg","name":"I’m OBVIOUSLY Shannon Crabill"},"published":null,"content":null}},{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/like/twitter/waterproofheart/1223233324820377602/64515860","wmProperty":"like-of","wmId":786355,"type":"entry","url":"https://twitter.com/waterproofheart/status/1223233324820377602#favorited-by-64515860","likeOf":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","author":{"url":"https://twitter.com/metalandcoffee_","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/b4ca7a2beac791acfd6c29952ea2dfad94e2fc039c3a6ebd07ab3d0a15e58c91.png","name":"Ebonie"},"published":null,"content":null}},{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/like/twitter/waterproofheart/1223233324820377602/702843209085534208","wmProperty":"like-of","wmId":786354,"type":"entry","url":"https://twitter.com/waterproofheart/status/1223233324820377602#favorited-by-702843209085534208","likeOf":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","author":{"url":"https://twitter.com/plopjs","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/e46e5e802f5968bac97291048d550bc3b630509e155e6b71e29f9546bc487c90.png","name":"Plop"},"published":null,"content":null}},{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/like/twitter/waterproofheart/1223233324820377602/15914886","wmProperty":"like-of","wmId":786353,"type":"entry","url":"https://twitter.com/waterproofheart/status/1223233324820377602#favorited-by-15914886","likeOf":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","author":{"url":"https://twitter.com/rebzmedia","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/d68d00b3c4b8c07ad97d4ffa6003f0751910036a57245a5f3412442f562c5460.jpg","name":"Chris Johnson"},"published":null,"content":null}},{"node":{"wmTarget":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","wmSource":"https://brid-gy.appspot.com/like/twitter/waterproofheart/1223233324820377602/14976849","wmProperty":"like-of","wmId":786352,"type":"entry","url":"https://twitter.com/waterproofheart/status/1223233324820377602#favorited-by-14976849","likeOf":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","author":{"url":"https://twitter.com/M_Altarriba","type":"card","photo":"https://webmention.io/avatar/pbs.twimg.com/04ab3a5f718fc90548bf43d949869151428ba38f88de1eb499db064c6fb37ba7.jpg","name":"M_Altarriba"},"published":null,"content":null}}]}},"pageContext":{"permalink":"https://www.aboutmonica.com/blog/2020-01-29-automating-file-creation-with-javascript/","slug":"/blog/2020-01-29-automating-file-creation-with-javascript/","prev":{"id":"9265b187-a105-5ef9-bd16-dbde62fa1238","frontmatter":{"title":"Finally(), I'll clean up my Promises!","category":null,"date":"2020-02-25T13:19:10.285Z","slug":"2020-02-25-finally","tags":null,"redirects":null},"fields":{"slug":"/blog/2020-02-25-finally/"}},"next":{"id":"5b2ac97b-4afa-57dc-ba80-32371b68ce0c","frontmatter":{"title":"2019 into 2020, Year in Review","category":["reflection"],"date":"2020-01-01T02:43:13.595Z","slug":"2019-year-in-review","tags":["Reflection"],"redirects":null},"fields":{"slug":"/blog/2019-year-in-review/"}}}},
    "staticQueryHashes": ["1977783444","764694655"]}