Rebuilding My local development environment and workflow

Posted by Jeff Beeman on Sun, 05/20/2018 - 13:20

Last week I talked about setting up a new project using BLT, Dev Desktop, and Lightning. Today, I’ll talk more about my local environment setup and give a brief overview of my development and deployment workflow.


As I discussed in the last post, PHP, Composer, and Git are all installed via Homebrew:

brew install php71 composer git;

A global version of Drush (8.1.15 as of this writing) is supplied by Dev Desktop. I find this global Drush version continues to be useful for older Drupal 7 projects I continue to maintain and for projects for which I haven’t yet updated alias files or do not yet contain Drush 9-compatible commands.

Drush for this project, though, is locally vendored (BLT requires Drush as a dependency). Drush takes care of discovering the right version to use via the Drush Launcher built into the global Drush 8. So, I don’t need to worry about calling the wrong version of Drush for my project. If you’d like to add Drush 9 to your own Composer-driven project, there are instructions over in the Drush documentation.

Local environment configuration

Dev Desktop provides its own versions of things like PHP, Drush, and MySQL. Because I’m running PHP and Composer via Homebrew but also running Dev Desktop, I’ve done a few things to setup my local environment so it utilizes the right tools from the right places.

The lines below from my .bash_profile provide path settings account for the locations of the various tools I’m using.

export PATH="/usr/local/bin:/usr/local/sbin:$HOME/bin:$HOME/.composer/vendor/bin:$PATH"

# Add Dev Desktop settings and paths.
# Does not add Dev Desktop's PHP path; PHP is installed via Homebrew.
export DEVDESKTOP_DRUPAL_SETTINGS_DIR="$HOME/.acquia/DevDesktop/DrupalSettings"
export PATH="/Applications/DevDesktop/mysql/bin:$PATH"
export PATH="$PATH:/Applications/DevDesktop/tools"

I keep my .bash_profile configuration in a public Github repository, so feel free to check out jrbeeman/dotfiles if you’d like to see other potentially useful config to pull into your setup.

Editor extensions and configuration

I’ve been using Microsoft’s Visual Studio Code for nearly all development over the past year, and I think it’s great.

The following extensions have been useful in turning VS Code into a robust PHP IDE. Note that some of these extensions were installed for JavaScript development, and I’m including them here as many Drupal projects require both.

  • Apache Conf
  • Code Outline
  • Document This
  • ESLint
  • Git History
  • Markdown All in One
  • markdownlint
  • MDTools
  • PHP Debug
  • PHP DocBlocker
  • PHP Formatter
  • PHP Intelephense
  • Snippets and Syntax Highlight for Gherkin
  • TSLint
  • Twig
  • Vagrantfile Support
  • vscode-icons

VS Code supports user- and workspace-level (project) configuration overrides. Here’s what I’m using.

User settings

These user settings perform basic font and text display configuration and turn on the nice icons provided by vscode-icons.

  "editor.fontSize": 14,
  "editor.wordWrap": "on",
  "workbench.iconTheme": "vscode-icons",
  "editor.tabSize": 2

Workspace settings

These workspace settings tell VS Code to treat Drupal’s various funky file extensions as the right language (files.associations) and to ignore several different folders when building its index (files.exclude). The primary change with files.exclude was the “deploy” folder, which can really confuse VS Code if not ignored due to it containing a full copy of the application after creating a build.

  "files.associations": {
    "*.module": "php",
    "*.install": "php",
    "*.inc": "php",
    "*.theme": "php",
    "*.info": "ini"
  "files.exclude": {
    "**/.git": true,
    "**/.svn": true,
    "**/.hg": true,
    "**/CVS": true,
    "**/.DS_Store": true,
    "deploy": true

General workflow

Committing work to Github

As I work, I’m pushing my changes out to Github. I won’t go into too much detail on that aside from saying the .gitattributes and .gitignore files provided by BLT do a lot of the heavy lifting you’d normally need to do when first configuring Git for a Composer-driven Drupal project. You can check out what BLT provides here:

Deploying to Acquia Cloud

At given points during the development process, I feel ready to run a build and deploy those changes to Cloud.

In order to deploy to Acquia Cloud using BLT’s deploy commands, I first had to configure blt.yml with Acquia Cloud as a remote:

  default_branch: develop
    cloud: '[email protected]:exodar.git'

Because of Composer and BLT, adding new modules and deploying the change to Acquia Cloud is as easy as the three commands below, where I’ve added the Markdown module to the Exodar project:

composer require drupal/markdown:^1.2;
git commit -am "EX-000: Add markdown-8.x-1.2";
blt artifact:deploy --commit-msg "EX-000: Example deploy to branch" --branch "develop-build" --no-interaction;

I’ll go into greater detail about BLT’s artifact build and deploy commands in later posts. Most deployment processes will be more complex than this, especially when working with a team. For example, the brief process outlined here doesn’t account for anything related to configuration management, automatically enabling newly added projects after deployment, etc. Those more sophisticated aspects of a site deployment workflow will come later as I continue to modernize the workflow for my personal site. For now, this is a good start and allows me to rapidly develop my personal site while still leveraging Composer and BLT.

Wrapping up

With my local development workflow setup, now I can rapidly iterate on my project using Composer to add new dependencies, Drush to configure them, and BLT to deploy them. I've also got a great IDE configuration, so working with my project's code is a joy.


Setting up a new project using BLT, Dev Desktop, and Lightning

Posted by Jeff Beeman on Sat, 05/12/2018 - 17:43

This is the first in a series of posts where I'll capture how I built a new Drupal 8 version of using BLT, Dev Desktop, and Lightning. In later posts, I’ll talk about other local development solutions, dependency management, content migration, and how BLT helps me build and deploy artifacts to Acquia Cloud.

I chose BLT because it addresses a host of tasks related to the development workflow I want to have for my site. It's Composer-driven and centered around building and deploying artifacts. I chose Lightning because it packages up a selection of Drupal site building tools I knew I'd want to have in my site. In particular, I wanted Lightning's media management and publishing workflow.


If you’re following along, you’ll need Dev Desktop, Git, and Composer. Fortunately, I had all these things installed and ready to go (be sure to start up Dev Desktop after installing it).

Other dependencies you’ll need are documented by BLT. If you’re on OS X, I recommend using Homebrew to install what you’ll need:

brew install php71 git composer;
composer global require "hirak/prestissimo:^0.3”;

Note: If you read the BLT docs, you will not need Drupal VM or Cog dependencies for what you're doing here. I may get to Behat much later, but don’t worry about those dependencies for now.

Create the project

BLT’s documentation for creating new projects is excellent. If you’re starting a new project, or if you’d like more details on each of these steps, I recommend checking it out.

Keeping with the naming theme I used throughout my rebuild, let’s call the new project Exodar (hopefully some of you will get the reference).

composer create-project --no-interaction acquia/blt-project exodar

Configure BLT

Once the project is created, you need to update blt/blt.yml with configuration for the project. Note that the file has many settings in it. The snippet below only includes lines relevant for initial setup of the project with Dev Desktop. Keep the rest of the default settings in your own file if you’re following along.

  machine_name: exodar
  prefix: EX
  human_name: 'Exodar'
    name: lightning
    protocol: http
    hostname: 'exodar.dd'
    port: ‘8083'

The settings above tell BLT that the project’s name is Exodar and the local site URL is http://exodar.dd:8083/

Configure local Drush options

Edit docroot/sites/default/local.drush.yml and set the URI to your local site URL:

  uri: 'http://exodar.dd:8083'

Add the new code base as a local site in Dev Desktop

Over in Dev Desktop, add a new site via the “Import local Drupal site…” option. You’ll need to select the docroot subfolder, and then change the “Local site name” value accordingly so that Dev Desktop doesn’t call it “docroot” for you. Finally, be sure to use PHP 7.1+.

Configuration dialog for the Exodar project in Dev Desktop

Run BLT’s setup process

blt setup

Run BLT setup task to execute the full initial setup process to build your code base. You’ll be asked if you want to drop your database tables. Say “yes” - it’s safe. You don’t have a site yet!


You now have a fully built code base and Drupal has been installed. From your project’s directory, use Drush to login:

drush -l http://exodar.dd:8083/ uli

Wrapping up

You now have the project built and usable inside of Dev Desktop! You can start doing any number of site building tasks in this new site, and I’ll cover more topics in follow-up posts:

  • Further tuning the local environment: I’ll cover a couple basic things around Drush, Composer, editor configuration, pushing my work out to Github, etc.
  • Module and configuration management lifecycle: Adding new modules and managing their configuration.
  • Creating a sub-profile: I like to manage my site as a sub-profile of Lightning, which allows me to override dependencies, add my own requirements, and continually test the process of rebuilding my site.
  • Deploying to Acquia Cloud: Connecting Dev Desktop to Acquia Cloud, as you would with “normal” a code base won’t work as expected at this point. Because you're in a BLT-based project, you’ll be using BLT to run the build and deployment process.

Let's see if this thing will turn on again...

Posted by Jeff Beeman on Sat, 05/12/2018 - 15:25

It’s been a very long time since I’ve blogged. Facebook (which I’ve all but officially quit using) and Twitter have allowed me to easily publish ephemeral and generally meaningless content. Any longer-form writing I’ve done has usually been for work. I’ve really started to miss blogging, owning the shape and format of what I write.

While I’ve kept my Drupal 7 site up to date despite not blogging for years, I’ve resolved to pick up the habit again. My first step was to update my site to Drupal 8, and this is my first post after that update. I’ll publish a series of technical posts about my process. 

More broadly, I’m inspired by folks who have been working to regain ownership of their content and data along the way. For example, I learned about POSSE through a series of posts by Dries about reclaiming control of his data. I’m unsure if I’ll go "full-POSSE,” but this new architecture will allow me to experiment with the idea while pushing me to publish more often in my own space. I’ll experiment with adding new types of data here, including short-form posts, images, embedded videos, and more.

Light-weight solution to provide custom view modes and suggest related templates in Drupal 7

Posted by Jeff Beeman on Sat, 05/24/2014 - 09:43

When it comes to providing custom view modes for entities in Drupal, most developers turn immediately to Display Suite or Entity View Modes. Display Suite is very powerful, but I've found it to be far too "heavy" for most of my use cases. In this case, by "heavy" I mean that the module does way more than I need it to. It does a lot of things I simply don't want on my site. Entity view modes is a lighter-weight approach to supplying additional view modes, but I found that even it was cumbersome when it came to managing my view mode configuration in an easily-deployable way.

I wanted a simpler solution, and I knew it couldn't be that hard to provide this functionality in a custom, streamlined module.

The code snippets below do the following:

  • Define new display modes. As you'll see, this is super easy to do in code.
  • Suggest node templates based on the view mode of the given node. e.g. a teaser template vs. a full display template.
  • Suggest page templates based on the node type being viewed. e.g. alter the page markup for Article nodes.
 * Implements hook_entity_info_alter().
 * Provide front-page feature and sub-feature view modes. Template suggestions
 * are provided in example_preprocess_node().
function example_entity_info_alter(&$entity_info) {
  $entity_info['node']['view modes']['front_feature'] = array(
    'label' => t('Front page feature'),
    'custom settings' => TRUE,
  $entity_info['node']['view modes']['front_sub_feature'] = array(
    'label' => t('Front page sub-feature'),
    'custom settings' => TRUE,

 * Implements hook_preprocess_node().
function example_preprocess_node(&$variables) {
  // Provide template suggestions based on the view mode.
  // Example 1: node__front_feature
  // Example 2: node__article__front_feature
  if (!empty($variables['view_mode'])) {
    $variables['theme_hook_suggestions'][] = 'node__' . $variables['view_mode'];
    $variables['theme_hook_suggestions'][] = 'node__' . $variables['type'] . '__' . $variables['view_mode'];

 * Implements hook_preprocess_page().
function example_preprocess_page(&$variables) {
  // Provide template suggestions based on the node type.
  // Example 1: page__node__article
  if (!empty($variables['node']->type)) {
    $variables['theme_hook_suggestions'][] = 'page__node__' . $variables['node']->type;

My two cents: In Drupal development, we all-to-often turn immediately to heavy-weight, all-encompassing solutions for extremely simple problems. Simple solutions that leverage Drupal core's great APIs are generally completely sufficient.

Related reading: Looks like I'm not alone in seeking a lean approach to D7 view modes and template suggestions. Check out this post by Brad Czerniak titled Lean Drupal with Content View Modes and Views.

Random video game music highlights 2013-2014 (orchestral)

Posted by Jeff Beeman on Mon, 04/14/2014 - 20:52

This is list is incomplete, entirely subjective, and presented in no particular order. Most of the music here is from games I personally played last year. I'm sure there are other excellent soundtracks from 2013 and early 2014, so let me know if you have any other recommendations!

A lot of the credit for this list goes to the Top Score podcast by Emily Reese, over at Classical MPR. Additional inspiration from Kotaku.

Bioshock Infinite



God Only Knows

Will the Circle Be Unbroken


The Message

The Gopher

Don't Starve

Main theme

Assassin's Creed IV

Sea shanties

Tavern song: "Here's a Health to the Company"

Flamenco tavern song

All instrumental tavern music tracks


The Beginning of a Journey

The Last of Us

Main Theme

The Quarantine Zone

Rayman Legends

Mysterious Swamps

Mariachi Madness

Babel Tower

Dive Another Day

The Legend of Zelda: A Link Between Worlds

Lorule Field

Ni No Kuni Soundtrack

14 World Map ~Another World~

Fire Emblem: Awakening

Don't Speak Her Name


On the Beach at Night

Tomb Raider

"A Survivor Is Born" Suite [LIVE In Sweden]

SOS Tower [Final Version]


Git subtree cheatsheet

Posted by Jeff Beeman on Wed, 07/24/2013 - 15:40

I needed a cheatsheet for some common commands I use day-to-day with git subtree. I don't intend this to be a full overview of how to use subtree, more just a reference for myself and anyone else interested.

Initial setup

Add the project as a remote

git remote add myproject-upstream [email protected]:myuser/myproject.git

Fetch the remote

git fetch myproject-upstream

Add the project

git subtree add --prefix=path/to/project myproject-upstream/master --squash

Daily work

Push to the remote project repository

git subtree push --prefix=path/to/project myproject-upstream master

Pull remote changes

git subtree pull --prefix=path/to/project myproject-upstream master --squash


An OS X Drupal development environment with Homebrew

Posted by Jeff Beeman on Wed, 01/16/2013 - 09:55

This is a collection of notes I took while setting up a Drupal-ready Apache / MySQL / PHP environment on OS X using Homebrew and PEAR / PECL. I believe it should work to recreate an environment from scratch, but I've not run through the notes from start to finish on a fresh environment to validate. Hopefully this will help you get your own environment up and running easily!

Note: Mark Sonnabaum's Megalodon might be of interest to you, as well. For me, it involved learning a few too many things, and I also wanted as much as possible in my environment to be handled via a package manager like Homebrew or PEAR.

Update: Per Mark, Megalodon does entirely use Homebrew and Chef, I just misunderstood it. I look forward to seeing what I can do with it, once I dig in and understand it a bit more.

Update: Thanks, @stevepurkiss, for pointing out the typo on the first line for brew tap... That's been fixed!

Update: Thanks, @cashwilliams, for pointing out some issues with the my.cnf and order of packages being installed. I've updated a couple of the instructions below to reflect his findings.

Update: I've added instructions for initial setup of Drupal coding standards for PHP Code Sniffer.


  • Write a small script that stops / starts all the services we install. Then, remove the auto-start bits (e.g. launchctl)

Install Homebrew and various packages

brew tap homebrew/dupes brew tap josegonzalez/homebrew-php brew install mysql brew install graphviz brew install memcached brew install php53 --with-mysql brew install php53-xhprof php53-xdebug php53-uploadprogress php53-apc php53-memcache

Update ~/.profile to use new PHP

PHP_PATH="$(brew --prefix php53)/bin" export PATH=$PHP_PATH:$PATH

Setup MySQL

unset TMPDIR mysql_install_db --verbose --user=whoami --basedir="$(brew --prefix mysql)" --datadir=/usr/local/var/mysql --tmpdir=/tmp mysql.server start $(brew --prefix mysql)/bin/mysql_secure_installation mysql.server stop mkdir -p ~/Library/LaunchAgents cp $(brew --prefix mysql)/homebrew.mxcl.mysql.plist ~/Library/LaunchAgents/ launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist

Setup memcached

ln -sfv /usr/local/opt/memcached/*.plist ~/Library/LaunchAgents launchctl load ~/Library/LaunchAgents/homebrew.mxcl.memcached.plist

Setup PHP

Create a PHP-specific log area.

sudo mkdir -p /var/log/php sudo chmod -R ugo+rw /var/log/php

Update /usr/local/etc/php/5.3/php.ini with some defaults.

error_log = /var/log/php/php.log date.timezone = "America/Phoenix"

Install additional pear libraries

pear config-set auto_discover 1 pear install pear install

Setup Drupal coding standards for PHP Code Sniffer

pear install PHP_CodeSniffer cd ~/Projects/drupal drush dl --package-handler=git_drupalorg coder sudo ln -sv /Users/jbeeman/Projects/drupal/coder/coder_sniffer/Drupal $(pear config-get php_dir)/PHP/CodeSniffer/Standards/Drupal

Fix sendmail

sudo mkdir -p /Library/Server/Mail/Data/spool sudo /usr/sbin/postfix set-permissions sudo /usr/sbin/postfix start

Update Apache config to load new PHP


Note: You'll want to change [username] to your user name.

/etc/apache2/httpd.confLoadModule php5_module /usr/local/Cellar/php53/5.3.18/libexec/apache2/ ...

Virtual hosts

Include /private/etc/apache2/extra/httpd-vhosts.conf Include /Users/[username]/Library/VirtualHosts/*.vhost

MySQL config

Create /etc/mysql/my.cnf

sudo mkdir -p /etc/mysql sudo touch /etc/mysql/my.cnf

Add some default settings:

[client] default-character-set=utf8

[mysql] default-character-set=utf8

[mysqld] default-storage-engine=InnoDB collation-server = utf8_unicode_ci init-connect='SET NAMES utf8' character-set-server = utf8

Performance tuning

max_allowed_packet = 128M innodb_buffer_pool_size = 160M join_buffer_size = 4M tmp_table_size = 64M max_heap_table_size = 64M sort_buffer_size = 6M read_rnd_buffer_size = 4M key_buffer = 16M max_allowed_packet = 16M thread_stack = 256K thread_cache_size = 8 table_cache = 16 innodb_flush_log_at_trx_commit = 2 query_cache_limit = 4M query_cache_size = 128M

Setup a new VirtualHost

Add a vhost file: ~/Sites/Library/VirtualHosts/drupal-demo.vhost

ServerName drupal-demo.localhost DocumentRoot /Users/jbeeman/Sites/drupal-demo Options All AllowOverride All Order allow,deny Allow from all ErrorLog /var/log/apache2/drupal-demo_error.log CustomLog /var/log/apache2/drupal-demo_access.log combined

Add the local domain to /etc/hosts drupal.localhost


Sending email on OS X from localhost via an ISP

Posted by Jeff Beeman on Wed, 02/15/2012 - 09:46

For a while now I've noticed that when I'm at home doing Drupal development, emails from my local development environment don't get sent. Then, I'll get somewhere else and - all of the sudden - all the backed-up emails will get sent out. I figured out that it's because my localhost had to be configrued to send the email via my Internet service provider's SMTP server. In my case, the ISP is Cox. I was able to make a quick configuration change, and now things are working great.

Open up /etc/postfix/ and find the section containing relayhost configuration. Just add a new line that looks something like this (replace with your ISP's SMTP server info):

relayhost =

Done! This was all it took for me. Depending on your ISP, you may also need to configure port or authentication information. In that case, you'll likely want to look for some additional documentation.

Upgrading to Emacs 23.2 on Ubuntu 10.04 (Lucid)

Posted by Jeff Beeman on Tue, 10/05/2010 - 08:12

I've been frustrated at the lack of an update for the Emacs package in Ubuntu 10.04. I've been using Emacs 23.2 for OSX and going back-and-forth between 23.2 and 23.1 is confusing, particularly in org-mode. So, I searched for how to effectively build Emacs 23.2 from source in Ubuntu and had trouble finding good instructions that would cover me for things like windowing, fonts, etc. Finally, in my search this morning, I came across a the Ubuntu Emacs Lisp project on Launchpad. These folks have already done all the hard work and bundled it up into a PPA (Personal Package Archive) that will work with your existing Ubuntu update tools (apt-get).

Here's how to add the PPA to your sources list and upgrade Emacs to 23.2:

sudo add-apt-repository ppa:ubuntu-elisp/ppa sudo apt-get update sudo apt-get upgrade

Yep, that's it!

I got a job at Acquia!

Posted by Jeff Beeman on Wed, 09/29/2010 - 07:58

Just over 6 years ago I joined ASU's University Technology Office as a young and admittedly very inexperienced developer. I was fortunate enough to spend the time since then working for folks with foresight and strategic vision that I've only recently started to appreciate. I've also been blessed to have been involved with projects that I feel proud to say are changing the face of education. In short, I've loved my work at ASU more than my clumsy writing can describe here.

The public university system is not without its critics -- I've frequently been one of them -- but ASU is different. In my six years with ASU, I've worked with some of the most talented, dedicated, passionate, and brilliant people I could ever imagine encountering in one place. My team mates in alt^I and UTO are phenomenal. I had an incredible and rewarding few years obtaining my masters in Educational Technology, where I met folks that have changed my life and informed my vision of innovation in education. I can say the same about my friends in CLAS, the Provost Communication Group, President's Office, ASU Foundation, Education, Engineering, Nursing, and the ASU community at large.

Sometimes, though, an opportunity comes by that would be unthinkable to pass up.

In a couple of weeks, I'll start a new job at Acquia. I'm joining their team as a Technical Consultant. The role is a little hard to define without using the word "consulting," but it essentially comes down to helping customers successfully deploy and work with Drupal-based solutions. In my dealings with the Drupal community, there are only a few companies that I've ever considered to be "I would drop everything to work there" types of places, and Acquia was one of them (Yes, ASU is that great of a place). Acquia brings a passion for and focus on enterprise-level, large-scale solutions and support that melds with my vision of Drupal as a "serious" web development framework. While they see it as a long-term player in the web software market, their vision is to ensure that Drupal remains accessible and usable, and that the barrier to entry continues to lower. Most importantly, they've managed to be great contributors to the Drupal community while developing a sustainable, strategic approach to the business side of things.

I really can't describe how excited I am about this new adventure. My work at ASU has been so rewarding, but the scope of possibilities with work at Acquia is unlimited. I'm both humbled and nervous to be headed off to work with some of the best Drupal developers in the world, in a company guided by the founder of Drupal itself, Dries Buytaert. The leadership team at Acquia share a bold vision for the future of Drupal - and open source in general - one that makes me feel confident in having placed all my chips on that table several years ago.

I'm fortunate enough to be staying in Phoenix, close to my family and friends. The consultant job is going to have me traveling all over the country, though, which is something I'm really looking forward to trying out. Acquia is located in Boston, and I think it's going to be great to spend time there and other places on the east coast, which is still relatively foreign land to me. I think my upcoming travel will afford me opportunities to meet some incredible people.

ASU is a wonderful place, and I hope that I'll remain in touch and work with many of you in the future. I've made countless friends at the university and consider it "my" school, so I'll definitely not be disappearing. I will always be a Sun Devil.

Subscribe to Home