Themes
Theme scaffold is an example of a Drupal theme.
We recommend creating a custom your_site_theme theme for your project to
place custom styling and front-end features specific to your site.
The theme uses the site machine name convention (your_site_theme in this
case), while modules use the abbreviated prefix (ys_ for your_site).
Front-end theming is often project-specific and subject to team preferences.
The provided your_site_theme scaffold demonstrates how custom themes can
integrate with the Vortex tooling and automations.
You can adapt it or replace it with your preferred theme.
Build system
The theme includes a Node.js-based build system composed of npm scripts
over Sass, PostCSS with
Autoprefixer, Terser, and
chokidar:
- SCSS compilation
- JavaScript concatenation and minification
- CSS auto-prefixing for browser compatibility
- Linting for both CSS (Stylelint) and JavaScript (ESLint)
- Watch mode for development
Build commands
cd web/themes/custom/your_site_theme
# Install dependencies
npm ci
# Build production assets
npm run build
# Build development assets (unminified)
npm run build-dev
# Run linting
npm run lint
# Auto-fix linting issues
npm run lint-fix
# Watch for changes during development
npm run watch
Ahoy commands are configured to call the appropriate npm scripts from the theme directory:
# Install front-end dependencies
ahoy fei
# Build production assets
ahoy fe
# Build development assets (unminified)
ahoy fed
# Watch for changes during development
ahoy few
# Lint front-end code
ahoy lint-fe
# Fix front-end lint issues
ahoy lint-fe-fix
These commands run within the container to use the Node.js environment and tools installed there, so every development environment runs them the same way.
When adding your own theme with a custom build system, it's a good idea to follow the same command structure and naming conventions. The commands then stay consistent across projects, and other developers can work with the build system without learning a new process.
File structure
The main directories and files (build outputs, lint configuration files, and static assets are trimmed for brevity):
your_site_theme/
├── .storybook/ # Storybook configuration
│ ├── main.mjs # Story sources and framework
│ └── preview.js # Story render endpoint
├── components/ # Single Directory Components (SDC)
│ └── button/ # Sample button component
│ ├── button.component.yml # Component schema (props and slots)
│ ├── button.twig # Component template
│ ├── button.stories.twig # Component stories
│ └── button.css # Component styles
├── scss/ # Sass source files
│ ├── _variables.scss # Theme variables
│ ├── _mixins.scss # Sass mixins
│ ├── _fonts.scss # Font definitions
│ ├── _rem.scss # REM unit utilities
│ ├── styles.scss # Main stylesheet
│ └── components/ # Component-specific styles
│ └── _header.scss # Header component styles
├── js/ # JavaScript source files
│ └── your_site_theme.js # Main theme JavaScript
├── templates/ # Twig template overrides
│ └── layout/
│ └── region--footer-bottom.html.twig # Renders the button component
├── tests/ # Theme tests
│ └── src/
│ ├── Unit/ # Unit tests
│ ├── Kernel/ # Kernel tests
│ └── Functional/ # Functional tests
├── your_site_theme.info.yml # Theme definition
├── your_site_theme.libraries.yml # Asset libraries
├── your_site_theme.theme # Theme functions
├── package.json # Node.js dependencies
└── logo.svg # Theme logo
Libraries
The theme defines asset libraries in your_site_theme.libraries.yml to load
its CSS and JavaScript with their dependencies.
Single Directory Components
The theme ships a sample Single Directory
Component
(SDC) in components/button and uses it from
templates/layout/region--footer-bottom.html.twig to render a "back to top"
link.
Components are validated with SDC Devel:
ahoy lint-sdc
➡️ See SDC Devel for how the validator is set up and where it runs.
Storybook
Storybook documents the theme's components and is enabled by selecting it during installation. Drupal renders every story through the Storybook module, so the library shows the same markup the site renders.
Stories are authored in Twig next to the component they document, as
<component>.stories.twig, and compiled into <component>.stories.json by
Drush. The compiled files are generated artifacts and aren't committed.
Working with Storybook
Like the other front-end commands, the Storybook commands run inside the CLI container, using the theme dependencies installed for it.
# Develop components: regenerate stories as they change and serve them live
ahoy storybook
# Refresh the component library served at /storybook
ahoy storybook-build
ahoy storybook generates the stories, starts a development server and
prints its address, such as http://localhost:55197, once the server is
ready. It keeps running until you press Ctrl+C, and regenerates the
stories whenever a *.stories.twig file changes, so new and edited stories
appear without a restart. Docker assigns the port when the container starts,
and ahoy info shows it next to the library address.
The development server runs on its own origin, so services.storybook.yml
shares story renders with localhost origins in the local, ci, and
dev environments. It replaces the cors.config from services.yml there,
so a site that already shares responses with other origins needs to list
them in services.storybook.yml too.
The component library at /storybook is a static copy built during
provisioning, so it doesn't change while you work. Run
ahoy storybook-build to regenerate the stories and rebuild it, for example
before sharing a change for review.
In the local environment, provisioning turns on Twig development mode. An
edit to a component's template then shows up in the development server and
the library on the next render, without a cache rebuild.
Customizing locations
The ahoy commands and provisioning run vendor/bin/vortex-storybook,
which reads its locations from environment variables. A project that moves
the theme or its stories sets them in .env instead of changing the
commands:
VORTEX_STORYBOOK_DIR- the directory with the Storybook configuration and its npm scriptsVORTEX_STORYBOOK_STORIES_PATTERN- the Twig story templates to watchVORTEX_STORYBOOK_DEV_SCRIPTandVORTEX_STORYBOOK_BUILD_SCRIPT- the npm scripts that start the development server and build the libraryVORTEX_STORYBOOK_PORT- the development server port inside the containerVORTEX_STORYBOOK_BUILD_SERVER_URL- the site that renders stories for the static library, when it isn't the site that serves it
The variables reference lists their defaults.
Running Storybook on the host
The theme's node_modules directory is shared with the CLI container, and
holds dependencies installed for the container's architecture. To run
Storybook on the host instead, reinstall the dependencies there, keep the
stories regenerating in the container, and point the development server at
the site's local URL shown by ahoy info:
cd web/themes/custom/your_site_theme
rm -rf node_modules && npm ci
# In a second terminal: regenerate the stories as they change
ahoy storybook-stories --watch
STORYBOOK_SERVER_URL=http://your-site.docker.amazee.io npm run storybook
The development server is then available at http://localhost:6006. Run
ahoy fei before using the ahoy front-end commands again, so the
container gets its own dependencies back.
Published component library
Provisioning installs the Storybook module with the other development
modules, then generates the stories and builds the static application into
the theme's storybook-static directory, which the web server serves at
/storybook. The build runs in the local, ci, and dev environments
only, which are the environments where the story render route is reachable.
Set DRUPAL_STORYBOOK_SKIP=1 to skip the build and shorten provisioning,
and run ahoy storybook-build to rebuild it on demand.
In the dev environment, Shield
protects the story render route, so a story renders only after the browser
has the Shield credentials. The web server serves the static application at
/storybook and its story index directly, so Shield doesn't protect them.
On Lagoon, the CLI and web containers run in separate pods, so a dedicated
persistent storybook volume keeps the storybook-static directory shared
between them. Acquia deployment artifacts carry no theme dependencies, so
the application isn't built there.
Tests scaffold
The tests directory contains working examples of tests that can be used as
a starting point in your project.
It also has a set of helper Traits that you may find useful when writing
your tests. Remove them if you don't need them.