Using Grunt with grunt-replace to replace handlebars/mustache with package.json variables

Recently while聽testing out some Node.js modules for Grunt I came across grunt-replace, and my first though was, this would be great for setting up boilerplate PHP files for my WordPress plugins. 聽Because I already set the name, slug, version, and other details in the聽 package.json聽file, it would be great to use a template I could create for PHP files and just use Grunt to take the details from 聽 package.json聽聽and setup my base plugin files using a template syntax like Handlebars or Mustache. 聽Luckily for me it worked out perfectly, but did require a little bit of troubleshooting and head scratching, but here’s how to make it work …
Below you will find an example聽聽 package.json聽file. 聽One thing to note,聽聽 name聽 has to be lowercase without spaces, I decided to just use that as the WordPress slug, but you could always add slug if you want.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
{ "name": "smyles-plugin", "title": "sMyles Plugin", "acronym": "sp", "version": "1.0.0", "homepage": "http://plugins.smyl.es", "author_homepage": "http://smyl.es", "class": "sMyles_Plugin", "CAP_NAME": "SMYLES_PLUGIN", "main": "Gruntfile.js", "devDependencies": { "grunt": "~0.4.2", "grunt-replace": "~0.7.8" }, "engines": { "node": ">=0.8.0", "npm": ">=1.1.0" } } |
As you can see above I added a few custom variables that will be used in the templates below. 聽You can add as many as you want, it all depends on your setup. 聽You will need to make sure that grunt-replace is in devDependencies, this can be done easily by running聽 npm install grunt-replace --save-dev
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
'use strict'; module.exports = function (grunt) { var pkg = grunt.file.readJSON( 'package.json' ); grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), replace: { dist: { options: { patterns: [ { match: /({{(\w*)}})/g, replacement: function ( match, offset, string, source, target ) { return pkg[string]; } } ] }, files: [ { expand: true, flatten: true, src: ['smyles-plugin.php'], dest: 'build/' } ] } } }); grunt.loadNpmTasks( 'grunt-replace' ); grunt.registerTask('setup', ['replace']); }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<?php /** * Plugin Name: {{title}} * Plugin URI: {{homepage}} * Description: * Author: Myles McNamara * Author URI: {{author_homepage}} * Version: {{version}} * Text Domain: {{plugin_text_domain}} */ Class {{class}} { const PLUGIN_SLUG = '{{name}}'; const PROD_ID = '{{title}}'; const VERSION = '{{version}}'; function __construct() { if ( ! defined( '{{CAP_NAME}}' ) ) define( '{{CAP_NAME}}', {{class}}::VERSION ); add_action( 'admin_enqueue_scripts', array( $this, 'admin_assets' ) ); } public function admin_assets() { wp_enqueue_style( '{{acronym}}-styles', {{CAP_NAME}}_PLUGIN_URL . '/assets/css/{{acronym}}.min.css' ); } } |
Above is an example plugin file that we will be replacing the Handlebars/Mustache template variables with our details from the package.json file. 聽I removed as much as I could from the PHP file to keep it as simple as possible. 聽Now we will go through each section to explain how it works.
The package.json file is pretty self explanatory, just setup whatever variables you want to use, and Grunt will pull the details from that file and replace them in your PHP file.
The Gruntfile.js is the meat of everything, but the main area you need to focus on is 聽 replacement聽 where the real magic happens…
1 2 3 4 |
match: /({{(\w*)}})/g, replacement: function ( match, offset, string, source, target ) { return pkg[string]; } |
The first line match uses RegEx to match the Handlebars/Mustache template variables, and replacement uses an anonymous function to return the data for replacement.
1 |
match: /({{(\w*)}})/g, |
Match will do just that, match (and group) all {{something}}聽, it will also group just the wording聽inside which in this case is something聽.
1 2 3 |
replacement: function ( match, offset, string, source, target ) { return pkg[string]; } |
The replacement section calls an anonymous function with all the attributes you see above, but we will only need a couple of them. 聽If you’re familiar with Grunt you already know that normally you could just use something like this to reference the object and not need to use an anonymous function:
1 |
replacement: '<%= pkg.name %>' |
Unfortunately this will not work for our case as that is an internal Grunt template string and we need to get the property value of the object based off a variable (which is obtained via RegEx). 聽So, the solution I found to this problem was to simply use an anonymous function, and then inside that anonymous function, reference the pkg聽聽object and the property based off our variable, which in this case is string聽.
The one thing I want to point out is that I had to load the pkg object at the top of the Grunt file in order to reference it in the replace anonymous function. 聽You will notice that pkg is defined right below the module.exports and right above the grunt.initConfig, this is required in order to work correctly.
1 2 3 4 5 |
module.exports = function (grunt) { var pkg = grunt.file.readJSON( 'package.json' ); grunt.initConfig({ |
That’s all there is to it! 聽You should now have a new file under the /build聽聽directory that has been updated with all of your details from the package.json聽聽file. 聽Profit!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<?php /** * Plugin Name: sMyles Plugin * Plugin URI: http://plugins.smyl.es * Description: * Author: Myles McNamara * Author URI: http://smyl.es * Version: 1.0.0 * Text Domain: undefined */ Class sMyles_Plugin { const PLUGIN_SLUG = 'smyles-plugin'; const PROD_ID = 'sMyles Plugin'; const VERSION = '1.0.0'; function __construct() { if ( ! defined( 'SMYLES_PLUGIN' ) ) define( 'SMYLES_PLUGIN', sMyles_Plugin::VERSION ); add_action( 'admin_enqueue_scripts', array( $this, 'admin_assets' ) ); } public function admin_assets() { wp_enqueue_style( 'sp-styles', SMYLES_PLUGIN_PLUGIN_URL . '/assets/css/sp.min.css' ); } } |