Rapid Drupal Scaffolding with Yeoman
Simple things should be simple, complex things should be possible.
– Alan Kay
The Console module in Drupal 8 has a lot of developers excited, seeing as it has built in support for scaffolding out and generating modules at the command line. This particular feature will put Drupal in line with some of the other more MVC-like frameworks out there, like Ruby on Rails or Laravel, which both have a suite of supporting libraries that take some pain out of development by generating reliable boilerplate code.
This is all well and good, but what about Drupal 7? The Drupal 8 release date may still be a bit far off, and even then many Drupal 7 sites will still need maintaining, as a lot of contrib modules will be slower still to make the complete switch. Yet, we can have our proverbial cake and eat it too. Yeoman is a language-agnostic scaffolding framework which relies on Node.js. By allowing the user of the generator to input specific variables to fit their needs, it gives you the flexibility of creating best-practices code on the fly, while still being unique to a specific use-case.
One Yeoman generator in particular that's proven particularly useful is Drupal Entities, which allows for rapid creation of Entities, i.e. the underlying class for Nodes, Content Types, and so on. It also proved to be an excellent example of how to make a Drupal-specific version of a generator—and was good inspiration to locate other common custom Drupal development tasks that could have their complexity mitigated. One common use case I've run into is creating custom Field and Views Formatters, in particular integrating a jQuery plugin to the output of a Views list or multivalued-field, while still preserving the formatter settings. Thus began my hacking.
We are already big fans of the Owl Carousel Module here at Echo, which is a fantastic integration of the Owl Carousel jQuery plugin with Drupal, and is utilized on a number of our sites. It not only provides Field and Views formatters, but also unlimited settings groups (controlling, e.g., speed, width and number of items in each carousel), which are dynamically assigned to variables in the DB, and then can be loaded individually in any number of instances on the front-end of the site (if you had more than one carousel on a page, for instance). To me, this presented the perfect architecture to make a generic version to use as a template for integrating other JavaScript plugins.
Essentially, the structure of the code that one makes generic to work with Yeoman mirrors the directory of the actual application/module, so in this case our file structure is incredibly familiar. Aside from our .json configuration files, you'll see our app directory (where the templates live) is loaded with some familiar Drupal file extensions: .module, .info, .install, etc.
We also have theme, submodule modules and includes directories which house more of these underscore-prefaced templates, which are essentially PHP files that Yeoman treats as plain text files. After the user is prompted for a number of values, (in this case, the name of the module, the name of the plugin being integrated, and some meta-information about the settings--i.e., whether it is a boolean, integer, or string), Yeoman traverses the templates, finding and replacing any reference to those variables, which are delimited by templating tags. Here's an example hook in one of these files with several variables that will be replaced by the user supplied values on the command line:
<?php
/**
* Implements hook_library().
*/
function <%= moduleName %>_library() {
$library = libraries_get_path('<%= libraryName %>');
$libraries['<%= pluginName %>'] = array(
'title' => '<%= pluginProper %>',
'website' => '<%= pluginSite %>',
'version' => array(),
'js' => array(
$library . '<%= relativeScriptpath %>' => array(
'scope' => 'footer',
),
),
'css' => array(
$library . '<%= relativeStylepath %>' => array(
'type' => 'file',
'media' => 'screen',
),
),
);
return $libraries;
}
So after paring the module down to its core and assuring every value was being dynamically populated, I tested out whether it all came together by generating a Module that integrates a JS plugin called oriDOMi. The result was that I only needed to perform maybe a half an hour of debugging—simply fixing the initialization method in the JavaScript so that it was calling on the correct nested JSON object settings group. Of course, many hours were spent getting the generator ready, but essentially this lays the groundwork to let developers focus on enhancing the front-end integrations they're doing, as opposed to worrying about how a client or even another developer will manage the inevitable need to change something as trivial as how fast something should animate. The resulting module is available online, if you'd like to see what the output looks like here.
Here's is a bonus pic of the result of that particular test generation:
Placeholder text generated from Gluten Ipsum.
The entire source of the generator itself is available at GitHub, where you can peruse the code. You'll find installation and usage instructions as well, and as always, if you've found something that could be improved, please fork and make a pull request! Additionally, an in depth guide to making your own generators for Drupal may be on the way—but until then, the documentation for Yeoman is a wonderful starting point.
Tags: codeyeomandrupalgeneratornode.jsphpmvcconsolecliyonpmmodule