<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Raine Revere</title>
    <description>The latest articles on DEV Community by Raine Revere (@raineorshine).</description>
    <link>https://dev.to/raineorshine</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F566107%2Fc14dcbe7-fdf5-4a7b-babb-2c5d29c85ee2.jpeg</url>
      <title>DEV Community: Raine Revere</title>
      <link>https://dev.to/raineorshine</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/raineorshine"/>
    <language>en</language>
    <item>
      <title>yogini: Simple, prompt-driven scaffolding for continuously evolving boilerplates</title>
      <dc:creator>Raine Revere</dc:creator>
      <pubDate>Sun, 24 Jan 2021 00:36:59 +0000</pubDate>
      <link>https://dev.to/raineorshine/yogini-simple-prompt-driven-scaffolding-for-continuously-evolving-boilerplates-4el0</link>
      <guid>https://dev.to/raineorshine/yogini-simple-prompt-driven-scaffolding-for-continuously-evolving-boilerplates-4el0</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/raineorshine/yogini/"&gt;yogini&lt;/a&gt; is a prompt-driven scaffolding system. It makes it easy to create and maintain personal boilerplates that evolve over time.&lt;/p&gt;

&lt;p&gt;What makes &lt;strong&gt;yogini&lt;/strong&gt; different?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prompt-driven (via &lt;a href="https://github.com/SBoudrias/Inquirer.js"&gt;Inquirer&lt;/a&gt;) with &lt;a href="https://github.com/raineorshine/yogini/blob/master/app/yogini.json"&gt;easy prompt configuration&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Embedded file-copying logic, e.g. &lt;code&gt;{useSass}main.scss&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Templating with &lt;a href="https://github.com/raineorshine/striate"&gt;striate&lt;/a&gt;, a superset of &lt;a href="https://github.com/mde/ejs"&gt;ejs&lt;/a&gt; with better handling of multi-line blocks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Generators created by yogini are &lt;a href="http://yeoman.io/"&gt;yeoman&lt;/a&gt; generators, so they can be published and consumed them like any other yeoman generator. You do not need to understand yeoman to use yogini.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; yo                 &lt;span class="c"&gt;# install yeoman&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; generator-yogini   &lt;span class="c"&gt;# install yogini&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Create your generator
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;generator-mygen             &lt;span class="c"&gt;# create a directory for your new generator&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;generator-mygen            
yo yogini                         &lt;span class="c"&gt;# generate a blank yogini generator&lt;/span&gt;
npm &lt;span class="nb"&gt;link&lt;/span&gt;                          &lt;span class="c"&gt;# alias your generator to your globally&lt;/span&gt;
                                  &lt;span class="c"&gt;# installed npm modules so that you can run&lt;/span&gt;
                                  &lt;span class="c"&gt;# it with yeoman.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Use your generator
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;mygen1                      &lt;span class="c"&gt;# create a directory for your new project&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;mygen1
yo mygen                          &lt;span class="c"&gt;# generate a new project&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;Would you like some generator with your generator? I know, it's a bit confusing. There are four levels to be aware of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;yo&lt;/strong&gt; - Ye ol' scaffolding framework. Does all the hard work, like a good yeoman. Kind of a pain to work with as a developer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;yogini&lt;/strong&gt; - Ye fancy &lt;code&gt;yo&lt;/code&gt; wrapper that makes it easier to create, evolve, and maintain your generator.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;generator-mygen&lt;/strong&gt; - Your personal generator. Name it whatever you want. Typically you'll have a single generator and use its powerful conditional prompts to control which files are copied for the desired project type.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;mygen1&lt;/strong&gt; - A cute little offspring from &lt;code&gt;generator-mygen&lt;/code&gt;. A fresh, new project!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building your generator
&lt;/h2&gt;

&lt;p&gt;An initial &lt;strong&gt;yogini&lt;/strong&gt; generator produces only a blank README, so you have to customize it to generate something useful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLDR;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drop files into &lt;code&gt;app/templates&lt;/code&gt;. All files from this directory will be copied into your project directory when you run the generator.&lt;/li&gt;
&lt;li&gt;Edit the &lt;a href="https://github.com/SBoudrias/Inquirer.js"&gt;Inquirer&lt;/a&gt; prompts in &lt;code&gt;app/yogini.json&lt;/code&gt;. These will determine which files get copied (via &lt;a href="https://github.com/raineorshine/prefixnote"&gt;prefixnotes&lt;/a&gt;) and what code gets copied (via &lt;a href="https://github.com/raineorshine/striate"&gt;striate&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1. Yogini file
&lt;/h3&gt;

&lt;p&gt;Sample yogini.json file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prompts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;confirm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Does your project use Javascript?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;confirm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Does your project use css?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above yogini.json file would prompt you with two questions every time you run your generator and store the answers in &lt;code&gt;js&lt;/code&gt; and &lt;code&gt;css&lt;/code&gt; variables. These variables drive the main two aspects of scaffolding: file copying and templating.&lt;/p&gt;

&lt;h4&gt;
  
  
  Advanced
&lt;/h4&gt;

&lt;p&gt;You can use a &lt;code&gt;yogini.js&lt;/code&gt; file and define a &lt;code&gt;parse&lt;/code&gt; function which allows you to transform or add to the user-provided answers to the prompts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prompts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;authorName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Raine Revere&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;authorUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://github.com/raineorshine&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;license&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ISC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;raineorshine&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;camelize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;prettyArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;

  &lt;span class="na"&gt;prompts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The prompts field also accepts a function which gets passed the generator instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prompts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;directory&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. File Copying
&lt;/h3&gt;

&lt;p&gt;You can control which files in &lt;code&gt;/app/templates&lt;/code&gt; get copied into your new project by prefixing filenames with expressions that include prompt variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── index.html
├── {js}scripts
│   └── main.js
└── {css}styles
    └── main.css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, the scripts folder will only be copied if &lt;code&gt;js&lt;/code&gt; (as declared in yogini.json) is true, and the &lt;code&gt;styles&lt;/code&gt; folder will only be copied if &lt;code&gt;css&lt;/code&gt; is true.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Empty expressions are a great way to include system and hidden files in your templates folder without them having an effect until they are copied:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;{}package.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{}.gitignore&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;If a folder name only consists of an expression, all files will be copied to the parent folder:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  main.js
  &lt;span class="o"&gt;{&lt;/span&gt;js&lt;span class="o"&gt;}&lt;/span&gt;
    ├── 1.js
    ├── 2.js
    └── 3.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;      ⇨&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  main.js
  1.js
  2.js
  3.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Expressions can be any Javascript expression that evaluates to &lt;code&gt;boolean&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="o"&gt;{&lt;/span&gt;js &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; gulp&lt;span class="o"&gt;}&lt;/span&gt;gulpfile.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;a href="https://github.com/raineorshine/prefixnote"&gt;prefixnote&lt;/a&gt; for the nitty-gritty.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Templating
&lt;/h3&gt;

&lt;p&gt;You can use &lt;a href="https://github.com/raineorshine/striate"&gt;striate&lt;/a&gt;, a superset of &lt;a href="https://github.com/mde/ejs"&gt;ejs&lt;/a&gt;, to control which code gets generated within the files. The answers given to the prompts in yogini.json are available as variables within the scope of your template files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &amp;gt;&amp;gt; if(css) {
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;'Stylesheet'&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;'text/css'&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;'styles/main.css'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &amp;gt;&amp;gt; }
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &amp;gt;&amp;gt; if(js) {
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;'scripts/main.js'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &amp;gt;&amp;gt; }
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see a complete yogini generator with prompts, file prefixes, and templating at &lt;a href="https://github.com/raineorshine/generator-yogini-sample"&gt;generator-yogini-sample&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  License
&lt;/h2&gt;

&lt;p&gt;ISC © &lt;a href="https://github.com/raineorshine"&gt;Raine Revere&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
    </item>
  </channel>
</rss>
