Drupal 8. Docker, composer, bootstrap, laravel-mix boilerplate. CI on GitLab

pexels photo 270360

I’ve created a simple boilerplate to rapidly develop Drupal application based on the technological stack we work day-to-day. Purpose of that was to implement new programmers in Drupal 8 environment in easy way.

The whole stack contains

Installation. Step by step

Start by creating new Drupal 8 instance from composer by calling

composer create-project drupal-composer/drupal-project:8.x-dev helloworld --stability dev --no-interaction

where helloworld is name of folder where the website will be stored.

Then we would merge this with a docker environment by cloning from docker4drupal and then copy the content of the drupal_docker_server into the helloworld folder

git clone git@github.com:wodby/docker4drupal.git drupal_docker_server
rm -R drupal_docker_server/.git
cp -R drupal_docker_server helloworld

Lets amend the volumes sections in drupal_docker_server/docker-compose.yml into

  volumes:
- ./../:/var/www/html

and setup localhost by changing traefik.frontend.rule

- 'traefik.frontend.rule=Host:localhost'

Now docker is ready to by launch

cd helloworld
docker-compose up -d

Visit http://localhost:8888/ to continue installation process. For database use the following settings

DB_HOST: mariadb
DB_USER: drupal
DB_PASSWORD: drupal
DB_NAME: drupal
DB_DRIVER: mysql

Drupal is installed now lets continue with setting up the frontend environment.

Docker composer and drush.

To call composer just run docker-compose exec php composer … and to run drush just call docker-compose exec php drush … for instance

docker-compose exec php composer update

or

docker-compose exec php drush config-export

Bootstrap 4 sub-theme.

Lets install bootstrap 4 Drupal theme

docker-compose exec php composer require drupal/bootstrap_barrio

now you need to copy files from subtheme folder into new custom theme. This way you would have sub-theme that extends main theme.

cp -R web/themes/contrib/bootstrap_barrio/subtheme web/themes/custom/helloworld 

where helloworldis custom name of your theme

Rename the following files from bootstrap_barrio_subtheme to helloworld:
bootstrap_barrio_subtheme.theme to helloworld.theme
bootstrap_barrio_subtheme.info.yml to helloworld.info.yml
bootstrap_barrio_subtheme.libraries.ymlto helloworld.libraries.yml
/config/install/bootstrap_barrio_subtheme.settingsto /config/install/helloworld.settings
/config/schema/bootstrap_barrio_subtheme.schemato /config/schema/helloworld.schema

Edit the file helloworld.info.yml

name: YourName
type: theme
description: 'Your Description.'
version: VERSION
core: 8.x
base theme: bootstrap_barrio
libraries:
- helloworld/global-styling

Delete the following:

# Information added by Drupal.org packaging script on 2015-11-29
# version: '8.x-4.0-beta1'
# core: '8.x'
# project: 'bootstrap_barrio'
# datestamp: 1448759945
# Information added by Drupal.org packaging script on 2018-04-30
# version: '8.x-4.9'
# core: '8.x'
# project: 'bootstrap_barrio'
# datestamp: 1525127885
# Information added by Drupal.org packaging script on 2018-05-27
version: '8.x-4.12'
core: '8.x'
project: 'bootstrap_barrio'
datestamp: 1527445384

Edit/config/schema/helloworld.schema.yml

# Schema for the configuration files of the Bootstrap Barrio Subtheme.
helloworld.settings:
type: theme_settings
label: 'YourTheme settings'

Edit /color/color.inc line 117

// Preview files.
'preview_library' => 'helloworld/color.preview',
'preview_html' => 'color/preview.html',

Edithelloworld.theme

Rename the function from:

function bootstrap_barrio_subtheme_form_system_theme_settings_alter($form, FormStateInterface $form_state)

to:

function helloworld_form_system_theme_settings_alter($form, FormStateInterface $form_state)

visit http://localhost:8888 login into admin panel, and enable the new theme.

Laravel-mix boilerplate

Once empty bootstrap sub-theme is installed lets establish scss and es6 deployment. We’re going to use superb laravel-mix package

Laravel Mix provides a fluent API for defining Webpack build steps for your Laravel application using several common CSS and JavaScript pre-processors. Through simple method chaining, you can fluently define your asset pipeline. For example:
mix
 .js('resources/js/app.js', 'public/js')
 .sass('resources/sass/app.scss', 'public/css');
If you’ve ever been confused and overwhelmed about getting started with Webpack and asset compilation, you will love Laravel Mix. However, you are not required to use it while developing your application. Of course, you are free to use any asset pipeline tool you wish, or even none at all.

To init the laravel-mix create new npm package and get the dependencies by calling

npm init 
npm i laravel-mix -s

We need to establish webpack settings and deploy scripts. Lest create in main folder next to package.json new file webpack.mix.js and put there the following contents

const THEMEDIR = "./web/themes/custom/helloworld";
let mix = require('laravel-mix');
mix
.browserSync({
proxy: 'localhost:8888',
files: [
`${THEMEDIR}/js/global.js`,
`${THEMEDIR}/css/*`,
]
})
.sass(`${THEMEDIR}/scss/style.scss`, `${THEMEDIR}/css`)
.js(`${THEMEDIR}/js/es6/global.js`, `${THEMEDIR}/js`)
.options({
processCssUrls: false
})
.sourceMaps();

and in package.json amend scripts section

"scripts": {
"dev": "NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch": "NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"hot": "NODE_ENV=development webpack-dev-server --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
"production": "NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},

and lets create web/themes/custom/helloworld/es6/global.js js file, which would be entry file for all out js scripts.

Once this is setup, calling scripts npm run watch launches browser sync at available port (most likely http://localhost:3000) and watches all the css and js changes. It runs browsersync so all the css changes are replaced without refreshing and all the js changes would refresh the browser. You change change browsersync settings in the webpack.mix.js file.

Script npm run prod compress css & js into production ready files.

Continuous Integration

Note that the following setup is good only for staging or test server, not for production use.

We’re going to use CI based on Gitlab. Basically after you push a code to develop branch this builds stage server by doing the following

  • pulls all the data from the git server, and merge files
  • update composer dependencies
  • clear drupal cache
  • import config from yaml files
  • deploy javascript and scss on the server by calling npm

You would need

  1. install the drupal instance on the server — this differs on each machine
  2. have composer and npm installed (or you could user composer.phar file like in example below)
  3. have access to the server by ssh key and add this key into GitLab variables. Ssh key is saved into $SSH_PRIVATE_KEY variable

First lets create deploy script build.sh. This is just an example you would have to change the values on your machine.

#!/bin/sh
cd /home/qunabu/webapps/helloworld
git fetch
git reset --hard HEAD
git checkout develop
git pull
php72 composer.phar update
php72 /home/qunabu/helloworld/vendor/drush/drush/drush cache-rebuild
php72 /home/qunabu/helloworld/vendor/drush/drush/drush config-import --yes
npm i
npm run dev
echo "success

Change access rights with chmod 700 build.sh and test with ./build.sh to see if everything works fine.

Once this step is ready what is left is to have GitLab to call it each time code on develop branch is pushed. Here is and example .gitlab-ci.yaml file

image: epcallan/php7-testing-phpunit:7.1-phpunit5
deploy_stage:
stage: deploy
variables:
GIT_STRATEGY: none
environment:
name: stage
url: http://helloworld.qunabu.com/
before_script:
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
- eval $(ssh-agent -s)
- ssh-add <(echo "$SSH_PRIVATE_KEY")
- mkdir -p ~/.ssh
- echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
script:
- echo "Deploy to staging server"
- ssh qunabu@qunabu.webfactional.com 'exec /home/qunabu/helloworld/mbps/build.sh'
  only:
- develop

Here is example from Gitlab console of successful build.

Resources


Drupal 8. Docker, composer, bootstrap, laravel-mix boilerplate. CI on GitLab was originally published in Qunabu Interactive on Medium, where people are continuing the conversation by highlighting and responding to this story.