All our Drupal projects are managed via Composer.
To start a new project, you have two options:
Use Drupal CMS : This will install Drupal and configure lots of default content, modules, image styles. This is ideal to have an already configured website with some content types etc... This is a good starting base for most website. Instructions here
Use drupal/recommended : This will get drupal core installed, and you then need to install any additional contrib modules that you need. Ideal for project where you want to configure everything yourself and avoid to have any default content/configuration. This is ideal for minimalist websites.
Our Drupal websites are mostly hosted on Pantheon or Platformsh. Some projects can be using other hosting and have then more customized steup.
Pantheon
If the project is using the Pantheon composer setup, then you don't need to commit the vendor folder generated by composer or the contrib modules & libraries, but if the project is using the standard mode where everything is tracked, don't forget to commit the files installed by composer.
For deploying on Pantheon, we are using Github actions that pushes to the Pantheon git repository. It also spin up a development environment at every pull request. See this example for the github actions setup: Example
The process will only deploy on the development environment of Pantheon, you then need to go on Pantheon dashboard and deploy on the test and live environment to have your changes live.
Platformsh
Platformsh is handling the installation of the dependencies through composer at every deploy, so the vendor folder, contrib modules & libraries should not be commited to the repository.
The github actions for platformsh are just pushing to the main branch on platformsh which will trigger a deploy automatically and the code will be live immediately.
If you need testing on a development environment, you need to spin an environment for your feature branch and push to the platformsh repository (not the github one) on that branch.
Example of github actions
The Drupal ecosystem is rich in free contrib modules. We have favorites modules to use, but the ecosystem is always evolving and you should also do your research and see if there is not a module that exists that does what you need. We will list below some of the important ones that we use usually.
When looking for modules, look for the date of the latest release. If it is very old, then it could be a sign that the module is poorly maintained and might have bugs. The number of sites using the module is also a good indicator to look at, if there are not many sites using it then it could be a bad sign. You can also check the evolution of the number of sites clicking on the number.
But it is always up to the developer to decide if it is worth it to use a module or not.
If it works well after testing, if the codebase of that module is very small etc...
It is advisable to keep the list of modules added via composer to a minimum and according to the actual needs of the project. The following is a list of modules that we have used on a number of projects and that are usually useful to add initially:
Admin interface
drupal/admin_toolbar
drupal/gin
drupal/gin_toolbar
drupal/entity_browser
drupal/field_group
drupal/focal_point
drupal/layout_builder_quick_add
drupal/layout_builder_restrictions
drupal/layout_paragraphs
drupal/masquerade
drupal/paragraphs
Ckeditor
drupal/linkit
drupal/ckeditor5_plugin_pack
drupal/ckeditor5_premium_features
Performance
drupal/redis
SEO
drupal/metatag
drupal/pathauto
drupal/rabbit_hole
drupal/schema_metatag
drupal/simple_sitemap
drupal/redirect
Development
drupal/ctools
drupal/devel
drupal/backup_migrate
drupal/token
drupal/webform
drupal/twig_tweak
drush/drush
drupal/image_effects
drupal/media_responsive_thumbnail
Integrations
drupal/google_analytics
drupal/symfony_mailer or drupal/symfony_mailer_lite
Spam
drupal/recaptcha
drupal/antibot
drupal/honeypot
Our current choice for an admin theme is Gin. It is listed as part of the default modules above.
For theme development, we do not use a specific base theme. We strongly recommend to use the folder structure of Drupal core themes such as Olivero, Stable or the starter_kit (see /web/core/themes). Custom themes should be placed in /web/themes/custom.
In order to build CSS and JS bundles the preffered approach is to use our most recent compiler setup. Franois would be the main contact if you do not find a recent one.
Core Build Tools:
Laravel Mix - The primary build tool that provides a clean API wrapper around Webpack 5, simplifying asset compilation and management
Webpack - The underlying module bundler that handles JavaScript transpilation and dependency resolution
Node.js- Specified in .nvmrc for consistent development environments
CSS/Styling Stack:
Sass/SCSS - CSS preprocessor with glob imports via node-sass-glob-importer for wildcard includes
TailwindCSS - Utility-first CSS framework configured with custom design tokens imported from Figma
PostCSS - Post-processing pipeline with autoprefixer and cssnano for optimization
Figma Design Tokens - Design system tokens automatically converted to Tailwind variables via figma-tokens-to-tailwind-variables
JavaScript Tools:
Babel - JavaScript transpiler configured with @babel/preset-env targeting ES modules
Alpine.js 3 - Lightweight JavaScript framework for component interactivity
Component Development:
Storybook 8 - Component development environment for building and testing Single Directory Components (SDC) in isolation
Drupal SDC (Single Directory Components) - Drupal's component architecture for reusable, encapsulated UI components
Build Process:
The webpack.mix.js configuration compiles:
Main theme SCSS (templates/main.scss) into css/main.css
SDC component SCSS from components/**/[^_]*.scss into their respective component directories
Standalone library SCSS from templates/*/**/[^_]*.scss into flat CSS files
Main theme JavaScript and component-specific JS files with source maps
Available Commands:
yarn install # Install dependencies
yarn dev # Watch for changes and run Storybook
yarn watch # Watch and compile assets (with polling)
yarn production # Build optimized production assets
yarn storybook # Run Storybook development server on port 6006
yarn build-storybook # Build static Storybook for deployment
If you are working on older projects, there could be a different setup. There are two approaches we usually used in the past: Using Gulp or Laravel Mix. Examples of build setups can be found in existing projects:
Reminders:
Wherever possible, make use of Drupal's libraries feature that allows CSS/JS to be added more targeted.
Avoid adding excessive logic into TWIG templates. Keep business logic in the THEME.template file via preprocess functions or add it via a custom module
Readability over extensibility! Avoid deep nesting and complex inheritance/extension of TWIG files.
Custom modules should be placed in /web/modules/custom. We recommend using the drush generate CLI in order to create module scaffolding as well as Plugins, Forms and Controllers.
When creating a custom module, ensure that all its functionality is encapsulated within it. Code produced by the module should not have to rely on CSS or JS that is part of the sites theme and vice versa. Ensure that configuration is properly removed upon uninstalling the module.
We encourage giving back to the Drupal community. So if you feel the module you are developing could be beneficial to the wider community, speak to Andrew about the possibility to turn your work into a contributed module.
Every image displayed on the website should be configured with an image style for performance purpose.
Recommendations:
Use responsive image styles
Use the convert Webp
Limit the sizes of the images using scale & crop
For images in headers, set the formatter to use loading="eager"
For images that are displayed at the top of the page in headers/hero blocks, also apply this code:
/**
* Implements hook_preprocess_responsive_image().
*
* Add fetchpriority="high" to responsive images in the hero block.
*/
function yourtheme_preprocess_responsive_image(array &$variables) {
// Make it fetchpriority="high" for performance reasons.
if (!empty($variables['responsive_image_style_id']) &&
$variables['responsive_image_style_id'] === 'your_image_style') {
// Add fetchpriority="high" to the img element.
if (isset($variables['img_element']['#attributes'])) {
$variables['img_element']['#attributes']['fetchpriority'] = 'high';
}
}
}
Both of these modules can be used to easily create custom layouts. Both have their pros and cons. Hence the decision which one to use depends on the project requirements. Here are a couple of points that might help with that decision:
Is the content also meant to exposed via an API? Then Paragraphs will be better because of it's build in integration to the Drupal core API modules.
Who will fill the various templates with content? If a more "page builder" experience is required where the client wants to be able to add content blocks, than Paragraphs, in combination with Layout Paragraphs, might be the better option. But if the developers populate various sets of templates and they are chosen via logic or by selection from the user, then Layout Builder would be the better option.
⚠️ Drupal is shifting towards Drupal Canvas but it is still experimental at the moment: canvas module
Potential areas where we need to do some research to improve our workflows and development.
Create custom Mellenger recipes for our sites - so we can configure / setup the base of the sites faster. We could potentially create some for features as well.
Watch Drupal Canvas, test to see when it is ready for us to switch and move away from the layout builder experience.