Web Developer, Open Source Software Enthusiast, Coffee Roaster, Sports Fanatic and Writer

Generate a Resume in DOCX and HTML at the Same Time

  • Posted: Mon Sep 07 2015 02:45:11 GMT-0500 (CDT)
  • Updated: Mon Sep 07 2015 03:55:56 GMT-0500 (CDT)

Tags:

How I use Assemble and Pandoc to generate my resume (in HTML and DOCX formats) from the same Markdown file, at the same time.

Background

When deciding to move my resume/portfolio/blog site from WordPress to an Assemble-generated static site, I wanted to find a way to generate my resume, in Word format, at the same time and from the same source as the HTML version. It's enough work to keep one copy of a resume up to date, let alone multiple formats.

Since I keep my resume in my Google Drive to ensure that recruiters and hiring managers can always grab the latest copy from this site, LinkedIn, etc., and since the formatting for a web version meant more work, I initially embedded the Word version in an iframe on my resume page. Not happy with that "solution", and already using a build script for the website (and thus the HTML version of the resume), I decided to see what it would take to automate the creation of the Word version as well.

At first, I (briefly, very briefly) considered converting or parsing the existing Word version of my resume to its HTML counterpart; anyone who has ever copied from a Word document and pasted that content into a WYSIWYG editor (such as that found in WordPress, Drupal, etc.), however, knows that Word mangles content - wrapping it in layer upon layer of needless span tags, among others.

While I still have to look up the syntax at times, writing with Markdown has been such a pleasure compared to the nightmare of constantly having to fix bad formatting (and trying to focus on writing) that is Word (or most other word processor applications).

I actually use LibreOffice most of the time, and it has a built-in converter for many formats, including DOC and DOCX, and there are even Node.js modules to interface with it (which my build script would need); however, it does not support conversion to or from Markdown.

Solution

Assemble uses Handlebars templates for layouts and partials (includes), YAML (and/or JSON) for data/variables which can be called from those templates, and one writes the actual content in Markdown (and/or native HTML). Since the majority of my resume is already in a Markdown file (which, when paired with a Handlebars layout, generates into an HTML page matching the rest of the site), I didn't want to manually rewrite the same exact content in yet another format.

Luckily, I discovered Pandoc, a command line program written in Haskell, which converts to and from a number of formats (including DOCX and Markdown). Even luckier, I discovered grunt-panda (Grunt plugin interface to Pandoc - Assemble builds my site through a series of Grunt tasks).

I won't go into the details of installing Assemble, Pandoc or grunt-panda (all of which are required for this), as their respective sites cover that, and I'll share my site (and now resume) builder on GitHub soon. I will share the ways I've incorporated them to work together.

Markdown

As previously mentioned, the resume content for both HTML and DOCX formats is converted from Markdown - the bulk of which resides in src/content/resume.md (the locations I mention will make more sense once my builder is on GitHub):

```md
---
layout: resume.hbs
rss: false
resumedownload: https://drive.google.com/file/d/0BxbBrLM2wSboNTRhcGxBZW9zZzA/view
description: Resume of Mike Bybee - Built with Markdown, converted to this webpage with Assemble and to Word document with grunt-panda (and Pandoc)
---

### CAREER HIGHLIGHTS

* Cut company’s web hosting costs in half while improving performance and response time.
* Tripled open/click-through rates of marketing emails by implementing responsive designs.
* Reduced page load times by 6 seconds on high-traffic, global nonprofit membership site.
* Reduced malicious traffic, blocking 99% of fake account creation (and 100% of fake account logins).

### SKILLS

* **DESIGN:** **Adobe Creative Cloud (CC)**, **Creative Suite (CS)**, **Dreamweaver**, **Photoshop**, **Fireworks, Illustrator**, GIMP, Inkscape, Bluegriffon
* **IDEs / EDITORS:** **NetBeans**, **Atom**, Eclipse, Visual Studio, VS Code, Brackets, TextWrangler, Sublime Text
* **LANGUAGES / SCRIPTING:** **HTML5**, XHTML, **CSS 3**, **PHP**, **JavaScript**, **Node.js**, **JSON**, YAML, Ruby, **VBScript**, ASP, **LESS**, **SASS**, Twig, Smarty, Moustache, Handlebars, Jade, Haml, CoffeeScript, Markdown, XML, XSLT, **BASH**, **Drush**, wp-cmd, BAT/CMD, **Powershell**
* **SYSADMIN / DEVOPS:** **Linux**, **Apache**, Nginx, **MySQL**/MariaDB/Percona, **PHP** **(LAMP/"LEMP" Stack)**, **MongoDB**, **AngularJS**, **Express**, **Node.js** **(MEAN Stack)**, IIS, cPanel, WHM, Plesk, Ajenti, ServerPilot, phpMyAdmin, SequelPro, Ansible, Chef, Puppet
* **PERFORMANCE / SCALABILITY:** **Redis**, **memcache(d)**, **mod\_pagespeed**, **CloudFlare**, **APC**, Zend Opcache, Varnish, Squid
* **FRAMEWORKS / LIBRARIES:** 960GS, HTML5 Boilerplate, Modernizr, **jQuery**, **jQuery UI**, jQuery Mobile, MooTools, **Zurb Foundation**, **Bootstrap**, Blueprint CSS, AngularJS, React, Cordova, Ionic, React Native
* **CMS / GENERATORS:** **WordPress**, **Drupal**, Joomla, MODX, **Jekyll**, **Assemble**, Metalsmith, Wintersmith
* **E-COMMERCE:** **ZenCart**, **PrestaShop**, **Magento**, **UberCart** (Drupal), **Drupal Commerce**
* **EMAIL / SOCIAL MEDIA:** Constant Contact, MailChimp, HootSuite, Buffer, IFFFT, Scoop.it!, Flipboard, APIs
* **VM / Containers:** **Vagrant**, VMWare ESXi/Server, Parallels, VirtualBox, Hyper-V, Xen, KVM, LXC, Docker
* **OS:** **Windows 2000-10/Server 2003-2012 R2**, **Mac OS X** 10.4-10.10, **Ubuntu**, Debian, **CentOS**
* **RUNNERS / BUILD SCRIPTS / DEP MANAGEMENT:** **Grunt**, **Gulp**, Make, Ant, **Composer**, **Bower**, NPM, Slush, **Yeoman**, apt
* **VERSION CONTROL:** **Git**, SVN, **GitHub**, **BitBucket**, Beanstalk, GitLab, **SourceTree**, GitKraken, TortoiseSVN, RabbitVCS
* **PROJECTS / TASKS / COMMUNICATION:** **Slack**, **Trello**, Gitter, HipChat, Asana, Pivotal Tracker, Microsoft Project, Outlook, Toodledo, Todoist, Wunderlist, Harvest, Timeneye, TimeCamp, Mavenlink

### WORK EXPERIENCE

#### Lead Full-Stack Developer / Curriculum, Course, and Interaction Designer, [**Edubiquity**](http://edubiquity.me)

##### **08/2015-Present, Remote**

* Developed Node.js-based automated platform for content curation and social media marketing tying into Buffer and other social APIs. 
* Developed custom RESTful LMS backend based on Drupal, with multimedia courses, curriculum, and tracker/planner features.
* Integrating Canvas LMS backend to allow additional 3rd party MOOC providers.
* Currently developing cross-platform, (nearly) single-codebase front-ends for web, Windows, Linux, OSX, iOS, and Android based on AngularJS and Ionic/Cordova (mobile) or Electron (desktop). 

**TECHNOLOGIES:** **Node.js**, **Drupal**, Canvas LMS, **H5P**, SCORM, TinCan xAPI, **Vagrant**, **AngularJS**, **Ionic**, **electron**, **Cordova**

#### Developer / Designer / Technical Writer, [**Multiple Clients and Agencies**](http://mikebybee.com/portfolio)

##### **08/2000-Present (Contract/Freelance), Remote**

* End clients include/have included: The University of Washington, RealNetworks, Oregon Metro, the State of Washington, Allied Feather and Down, and many more.
* Developed custom notifications for content editors, links to related (on- and off-site) articles, custom real-time traffic maps, camera feeds, and alerts, etc.
* Developed intranet sites for internal communication, employee benefits portals, etc. based on PHP, Node.js, Drupal, classic ASP (VBScript).
* Wrote user guides for writers/editors/site managers of CMS sites.
* Developed custom CMS/shopping cart modules/plugins and responsive themes, responsive website retrofits/redesigns.
* Designed logos, PDF menus, cut vector and printed raster signage, edited photos, and created other graphics.
* Wrote DevOps provisioners for development, staging, and production servers with Vagrant and BASH.
* Writing Markdown/WYSIWYG editor desktop application capable of multiple output formats (HTML, PDF, DOCX, PPTX) based on Electron, Node.js, and Pandoc.

**TECHNOLOGIES:** **Drupal**, **Vagrant**, Pandoc, **Node.js**, **HTML5**, **CSS 3**, jQuery, **Bootstrap**, **LESS**, **Gulp**

#### Systems Administrator / Full Stack Web Developer, [**Euphorie Massage**](http://euphoriemassage.com/)

##### **03/2010-Present (Spare-time), Seabrook, TX (Primarily Remote)**

* Migrating to **WordPress** with custom responsive theme and shopping cart for gift card sales and online appointment booking with Google Calendar integration.
* Designed responsive/mobile-friendly email marketing templates, increasing read rates.

**TECHNOLOGIES:** APC, CloudFlare, **mod\_pagespeed**, **HTML5**, **CSS 3**, **jQuery**, **Bootstrap**, **LESS**, **Gulp**

#### Owner / Roaster / Web Developer, [**enlightenCOFFEEroasters**](http://enlightencoffee.com/)

##### **02/2010-Present (Spare-time), Webster, TX**

* Developed bare **PHP**/**jQuery UI**/**CSS3** site with ecwid shopping cart for online orders.
* Migrating to **Drupal Commerce** with Solr product search for better SEO/store/content management.

**TECHNOLOGIES:** **memcache**, **APC**, **MongoDB**, CloudFlare, mod\_pagespeed, **HTML5**, **CSS 3**, **jQuery UI**

#### E-Learning Web Developer – Content Migration, Automation & UI/UX, [**Dell Inc.**](http://dell.com/)

##### **07/2014-07/2015 (Contract), Round Rock, TX (Remote)**

* Created a custom DITA Open Toolkit **XML**/**XSLT** plugin for SDL LiveContent Architect.
* Developed **NW.js (Node-Webkit)** application to convert multi-page HTML reference material to single-page format with anchor link navigation in **Oracle Knowledge** (with separate print-only CSS).
* Led coding standards effort among front-end developers, improved UI/UX for LMS.
* Wrote custom jQuery **AJAX** 5-star rating and feedback form (with Google Forms/Sheets back-end).
* Assisted Learning and Development team in creation of mobile-friendly content in **Saba LMS**.

**TECHNOLOGIES:** **Saba LMS/Cloud**, DITA OT, **Node.js**, **Grunt**, **Git**, HTML5, CSS 3, Bootstrap, LESS, JSON

#### Front End Developer / Web Content Manager, [**University of Texas Medical Branch (UTMB)**](http://www.utmb.edu/)

##### **01/2014-05/2014 (Contract), Galveston, TX**

* Migrated HTML 4.01 table-based ASP/ASP.NET 2.0 to responsive HTML5/CSS 3 ASP**/**ASP.NET 4.0.
* Assisted/educated other developers in use of **HTML5**, **CSS3 pseudo-selectors**, **Foundation**, **jQuery**
* Improved load times, compatibility errors, custom JavaScript/CSS/ASP in websites/templates.
* Wrote custom **jQuery** multi-level menu highlighting, **HTML5** form validation/ASP spam honeypot back-end.

**TECHNOLOGIES:** **ASP**, ASP.NET C\#, **Zurb Foundation**, **HTML5**, **CSS 3**, **IIS**, **SASS**, **Grunt**, Prepros

#### Full Stack Web Developer / Web Content and Marketing Manager, [**Supply Chain Council, Inc.**](http://supply-chain.org/)

##### **01/2013-01/2014 (Contract), Cypress, TX (Remote)**

* Improved security, stability, performance through **CDN**, **DNS/spam filtering**, IP blacklist lookup.
* Wrote Drupal module to assign user role based on employee status and company's member status.
* Managed social networks and curated content via APIs, HootSuite, Buffer, Scoop.it!, Flipboard, etc.
* Improved PageSpeed/YSlow scores to 97, scaled via **memcache**, **APC**, **CloudFlare**, cache modules.
* Migrated 30,000+ user Drupal 6/CiviCRM 3 site (with corrupted database) to Drupal 7/CiviCRM 4.

**TECHNOLOGIES:** **Drupal**, **Drush**, **HTML5**, **CSS 3**, jQuery UI, **Bootstrap**, **LESS**, git, OS X, Mavenlink

#### Systems Analyst, [**University of Texas MD Anderson Cancer Center**](http://mdanderson.org/)

##### **07/2012-01/2013 (Contract), Houston, TX**

* Pre-staged and joined Windows and Mac desktops and laptops to Active Directory domain via **Likewise**.
* Encrypted Windows 7 and Mac desktops and laptops with **WinMagic SecureDoc full-disk encryption**.

**TECHNOLOGIES:** **Windows XP-7**/**Server 2008 R2**, **OS X**, Quest ActiveRoles Server, **XenServer**, **Altiris**

#### Systems Administrator, [**Futron Corporation**](http://futron.com/)

##### **03/2012-07/2012 (Contract), Houston, TX**

* Assisted developers with **IIS**, DLL, **PHP** and FastCGI setup on Windows Server 2003-2008 web servers.
* Racked, set up and managed **Windows Server 2003-2008** file, print, and web servers.
* Wrote **VBScript** to migrate printers from Server 2003 to 2008, with user default chosen via HTA GUI.

**TECHNOLOGIES:** OS X, Powershell, **CMD/BAT**, **PHP**, **IIS**, **Avast! Professional Antivirus** (via **ADNM**)

#### Client Support Technician / Anti-Virus Administrator, [**Xvand Technology Corporation**](http://isutility.com/)

##### **10/2008-09/2010, Houston, TX**

* Assisted client developers with PHP and classic ASP (VBScript) web development/troubleshooting.
* Created and administered managed anti-virus as a service that was pure profit after 3 months.
* Created custom live CD with scripted multi-engine virus scan, hardware tests, password recovery, etc.

**TECHNOLOGIES:** **Windows 2000-7**/**Server 2003-2008 R2**, WhatsUp, WireShark, Kaspersky Anti-Virus

### EDUCATION

##### **Bachelor of Science**, Information Technology – Software Focus, Western Governors University, Online, 2016 (currently pursuing)

* Java/Perl/JavaScript development, Web/DB Design, Project Management, Technical Writing curriculum.
* Developed Java applications to manage contacts and to estimate students' remaining terms and cost.

##### **Associate of Applied Science**, Computer and Network Administration, Remington College, Webster, TX, 2012

* Distinguished Graduate Award, President's List – 4.0 GPA, Perfect Attendance
* Assisted instructors in setup of **Moodle** courses with **SCORM** compliance

##### **General Diploma**, Alief Hastings High School, Houston, TX, 1998

* Honors English IV, Honors German V, German Club, Literary Magazine

### CERTIFICATIONS

* 2x **CompTIA** – **Project+ 2009**, **Security+ 2011**
* **CIW Web Development Professional**
* 4x **CIW Specialist** – Database Design, Javascript, Perl, Web Design
* 2x **Microsoft Specialist** (**MS**) – Server Virtualization with Hyper-V and System Center, Programming in HTML5 with Javascript and CSS3
* 2x **Microsoft Certified Solutions Associate (MCSA)** – Windows Server 2008, Windows 7
* 2x **Microsoft Certified Information Technology Professional** (**MCITP**) – Windows Server 2008 Server Administrator, Windows 7 Enterprise Desktop Support Technician
* 3x **Microsoft Certified Technology Specialist** (**MCTS**) – Windows Server 2008 Network Configuration**,** Windows Server 2008 Active Directory Configuration, Windows 7 Configuration
* **Microsoft Certified Desktop Support Technician** (**MCDST**) – Windows XP

### MISCELLANEOUS

* **Extracurricular:** Web/graphic design, computer repair freelancer since age 19. Enthusiastic advocate of open source software. Turned passion for specialty coffee into artisan roasting business. Udemy/Lynda.com/etc. student outside of college.
* **Personal:** Avid reader of tech sites/blogs, classic literature. Dedicated student pursuing no less than a Master's Degree (Possibly dual: Web Development/Information Security). Computer musician/producer in spare time.
```


You'll notice that this only contains the "meat" of my resume - not the header, footer, links, etc. you see on the HTML version (and all pages of this site), nor the name and personal info (phone, email, and links to this site, my LinkedIn and GitHub profiles) you find at the top of the DOCX version.

You'll also notice some extra text at the tomp of the markdown file, between separators of three hyphens (---). This is called YAML Front Matter, or YFM. It is used to set variables, which can later be called in Handlebars tags in the page, partial, or layout template.

Creating the HTML version with Handlebars

In Assemble, the layout YFM variable is also used to set the layout template to be used when generating a given Markdown (or Handlebars) file. That is where the HTML version of my resume gets the aforementioned extras that make it a complete webpage (src/templates/layouts/resume.hbs in this case):

```hbs {{> head }} <body> <header> {{> navigation }} <h5 class="subtitle">{{{site.subtitle}}}</h5> </header> <main> <div class="row"> <div id="container" class="small-12 column"> {{> browse-happy }} {{#markdown}}

Resume

<a target="_blank" href="{{resumedownload}}" title="View on Google Drive">Latest Resume (Word Document, Synced via <i class="fi-social-drive icon-medium"></i> Google Drive)</a> {{> body }} {{/markdown}} </div> {{> ads }} </div> </main> {{> footer }} {{> scripts }} {{> google-analytics }} </body> </html> ```


Each section contained in double curly braces ({{ ... }}) is a Handlebars tag. The {{> body }} tag tells the layout where to load HTML or Markdown content of a given .hbs or .md file. The {{#markdown}}...{{/markdown}} tags tell the template to allow Markdown within them (rather than just HTML, the default). The other {{> ... }} tags load partials (sections of the layout saved to separate files for reuse across pages), from the src/templates/partials/ in this case. From this layout, the partials it includes, and the initial Markdown file, the HTML page is assembled by, well, Assemble.

Creating the DOCX version with Pandoc

The DOCX version is an entirely different animal. With Pandoc, one would normally initiate conversion via command line, such as:

$ pandoc -s --reference-docx=template.docx -o resume.docx top.md resume.md

I'm actually using an additional Markdown file, src/resume/top.md, which contains my name and personal information and goes before the aforementioned "meat" of src/content/resume.md in the DOCX version only:

```md

MICHAEL R. BYBEE

Webster, TX | (832) 305-6533 | [email protected]
Portfolio & Blog | LinkedIn | GitHub

```


Additionally, I'm stealing the styles from another DOCX file (which, in my case is just a previously generated version of my resume in which I changed the relevant styles and saved as src/resume/template.docx). The --reference-docx switch in the pandoc command above specifies the template from which to grab the styles (and trust me, you want one - by default, the DOCX generated by pandoc is hideous).

Using Grunt, Assemble, and grunt-panda to Create Both in one fell swoop

Thanks to grunt-panda, the conversion can be scripted into a task within the Gruntfile that also calls Assemble to build the website (note the comments, they specify what each item does):

'use strict';
/** The following lines create a cross-platform function to get the user's home directory */
var path = require('path');
function getHomeDir() {
  var dirpath = path.join.apply(path, arguments);
  var homepath = process.env[process.platform === 'win32' ? 'USERPROFILE' : 'HOME'];
  dirpath = path.resolve(homepath, dirpath);
  return dirpath;
}
/** END cross-platform user home directory function */

  module.exports = function(grunt) {

  /** WAY Condensed task list */
  grunt.initConfig({

    /** Set path variables to be called shorthand (lodash templates) */
    paths: {
      src: 'src',
      dist: 'dist',
      tmp: '.tmp',
      assets: '<%= paths.dist %>/assets',
      content: '<%= paths.src %>/content',
      data: '<%= paths.src %>/data',
      templates: '<%= paths.src %>/templates',
      bower: 'bower_components',

      /** Generated DOCX resume will be saved here, to be synced to Google Drive by desktop app (Grive2 + Google Drive Indicator in my case). */
      /** I haven't used the Windows or Mac version of the Google Drive app in ages, but I believe the directory is the same. */
      /** Change to your Dropbox, OneDrive, Copy, or other directory if you prefer to sync with another cloud sync/storage service. */
      googleDrive: getHomeDir('Google\ Drive/')
    },

    /** assemble task, which builds the entire website (including resume.html) */
    assemble: {
      options: {
        layoutdir: '<%= paths.templates %>/layouts',
        layout: 'site.hbs',
        partials: '<%= paths.templates %>/partials/*.hbs',
        assets: '<%= paths.assets %>',
        data: '<%= paths.data %>/*.{json,yml}',
        helpers: ['<%= paths.templates %>/helpers/*.js'],
      },
      dist: {
        files: [{
          expand: true,
          cwd: '<%= paths.content %>/',
          src: '**/*.{md,hbs}',
          dest: '<%= paths.dist %>/'
        }] 
      }
    },

    /** panda task combines top.md and resume.md, converting them to DOCX, with styles based on template.docx */
      panda: {
      resume: {
        options: {

          /** sets command line switches pandoc gets called with in the background */
          /** --reference-docx switch specifies a template file to copy styles from */
          pandocOptions: '-f markdown --smart --reference-docx=<%= paths.src %>/resume/template.docx'
        },
        files: {

          /** file before the : is the destination file, files after : and in square brackets are source files */
          '<%= paths.googleDrive%>/Resume/Resume_MichaelBybee_WebDev.docx': [
            '<%= paths.src %>/resume/top.md',
            '<%= paths.content %>/resume.md'
          ]
        }
      }
    }
  });

  /** Load required grunt plugins */
  grunt.loadNpmTasks('assemble');
  grunt.loadNpmTasks('grunt-panda');

  /** WAY simplified default task, simply type "grunt" from the commandline and press enter to build both website and DOCX resume */
  grunt.registerTask('default', [
    'assemble',
    'panda:resume'
  ]);
};


Again, this example Gruntfile is extremely simplified for clarity's sake. Yours will probably have numerous other tasks (such as less or sass for CSS preprocessing, uglify/htmlmin/cssmin/etc. for minification, and others).

Once you have yours set up, open a terminal/command prompt/whatever your OS calls it, cd to the directory where your Gruntfile.js resides, and issue the command $ grunt (or "grunt watch", "grunt server", or whatever other task you use).

Both your entire website (with a resume.html page) and a resume in DOCX format will be built with that single command.

Comments Powered by Google Forms

No comments so far...

Leave A Comment