一键导入
performance
Drupal performance optimization expertise. Use when working on caching, database queries, asset optimization, lazy loading, BigPipe, or profiling.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Drupal performance optimization expertise. Use when working on caching, database queries, asset optimization, lazy loading, BigPipe, or profiling.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when reviewing Drupal code for standards compliance across PHP, JavaScript, CSS, Twig, YAML, SQL, and markup — dynamically loads relevant standards per file type using Drupal's official community guidelines.
How to write, modify, and style React components for Drupal Canvas and Drupal CMS. Covers the technology stack (React 19, Tailwind CSS 4, CVA variants, cn utility), component.yml prop and slot definitions, enum naming, image and video prop types, formatted text fields, color scheme variants, theme tokens from global.css, required folder structure (index.jsx + component.yml), and matching source site visual styles including extracting design tokens, dark backgrounds, gradient text, glass/blur effects, and updating global.css theme. Use when building, editing, or fixing any component in src/components/.
Managing content in Drupal CMS via JSON:API. Covers listing, fetching, creating, updating, and deleting pages and content entities using npm run content commands. Includes page component structure (uuid, component_id, inputs, parent_uuid, slot), image uploading and media target_id handling, formatted HTML text fields, UUID generation, input format reference mapping component.yml prop types to JSON formats, menu item listing (menu_items--main, menu_items--footer, menu_items--social-media are read-only via API — must use admin UI for create/update/delete), page path alias management, and common pitfalls like wrong media IDs, link props as objects instead of strings, plain strings for HTML fields, target_id as integer instead of string, langcode errors, and JSON:API read-only mode. Use when composing pages, adding components to pages, uploading images, or interacting with the Drupal CMS content API.
Search and fetch Canvas and Drupal CMS documentation pages. Takes a query describing what you need to know (e.g., "code components", "page regions", "known issues", "data fetching") and returns the full content of matching documentation pages. Invoke with /canvas-docs-explorer <query>. Use this whenever you need to understand how Canvas or Drupal CMS works, verify platform behavior, check for limitations, or find configuration options.
Use when setting up a new Drupal CMS project with Canvas for component development. Covers DDEV, JSON:API write mode, Canvas OAuth client, permissions, page regions, menus, project scaffolding, .env, CSS layer fix, and Storybook validation. Every step is idempotent — safe to re-run.
Step-by-step guide for scaffolding a new React component from scratch. Covers copying an existing component as a base, creating the required index.jsx and component.yml files, naming conventions (snake_case machineName, no project prefixes), creating the matching Storybook story file, reusing existing components via imports, composability patterns, and internal component setup (status false). Use when a needed component does not yet exist in src/components/ and must be created.
| name | performance |
| description | Drupal performance optimization expertise. Use when working on caching, database queries, asset optimization, lazy loading, BigPipe, or profiling. |
You are an expert in Drupal performance optimization across all layers.
Drupal has multiple cache layers. Optimize from outermost to innermost:
Browser Cache
└─ CDN / Reverse Proxy (Varnish)
└─ Page Cache (anonymous users)
└─ Dynamic Page Cache (authenticated users)
└─ Render Cache (blocks, entities, views)
└─ Internal Cache (config, discovery, etc.)
For anonymous users, entire pages are cached. Configure at /admin/config/development/performance:
// settings.php — max-age for page cache
$config['system.performance']['cache']['page']['max_age'] = 86400; // 24 hours
When it works: Anonymous users, no session, no personalization. When it breaks: Any per-user content, CSRF tokens, form tokens.
Caches render arrays for authenticated users using cache contexts to vary output.
Key cache contexts:
user — per useruser.permissions — per permission set (most efficient for auth users)user.roles — per role combinationurl.query_args — varies by query stringurl.path — varies by pathsession — per sessionlanguages — per languageAll render arrays MUST include cache metadata:
$build = [
'#markup' => $content,
'#cache' => [
'tags' => ['node:123', 'node_list'],
'contexts' => ['user.permissions'],
'max-age' => 3600,
],
];
Cache tag conventions:
node:123, user:456, taxonomy_term:789node_list, user_listconfig:my_module.settingsmy_module:custom_tagInvalidation:
// Invalidate specific tags
\Drupal\Core\Cache\Cache::invalidateTags(['node:123']);
// Entity saves auto-invalidate their tags
$node->save(); // Invalidates node:{nid} and node_list
BigPipe sends the page shell immediately and streams personalized content later.
Use lazy builders for personalized or uncacheable content in an otherwise cacheable page:
$build['user_greeting'] = [
'#lazy_builder' => [
'my_module.greeting_builder:build',
[$uid],
],
'#create_placeholder' => TRUE,
];
// Service class
class GreetingBuilder {
public function build(int $uid): array {
return [
'#markup' => $this->t('Hello, @name', ['@name' => $user->getDisplayName()]),
'#cache' => [
'contexts' => ['user'],
'tags' => ['user:' . $uid],
],
];
}
}
Register as a service with #[AutowireLocator] or in *.services.yml.
// BAD: N+1 — loads each entity individually
foreach ($nids as $nid) {
$node = $this->entityTypeManager->getStorage('node')->load($nid);
}
// GOOD: Single query, bulk load
$nodes = $this->entityTypeManager->getStorage('node')->loadMultiple($nids);
$query = $this->entityTypeManager->getStorage('node')->getQuery()
->accessCheck(TRUE)
->condition('type', 'article')
->condition('status', 1)
->range(0, 50) // Always limit results
->sort('created', 'DESC');
$nids = $query->execute();
// Bulk load results
$nodes = $this->entityTypeManager->getStorage('node')->loadMultiple($nids);
// Use specific fields instead of loading full entities
$query = $this->database->select('node_field_data', 'n');
$query->fields('n', ['nid', 'title']); // Only needed columns
$query->condition('n.type', 'article');
$query->range(0, 50);
$query->addTag('node_access'); // Respect access control
$results = $query->execute();
// In hook_schema() or hook_update_N()
$schema['my_table'] = [
'fields' => [...],
'indexes' => [
'status_created' => ['status', 'created'],
],
];
Always configure cache on Views:
| Cache Type | Use When |
|---|---|
| Tag-based | Content changes unpredictably (default, recommended) |
| Time-based | Content changes on a schedule |
| None | Never (except during development) |
// Custom Views field plugin with optimized query
public function query() {
// Add only needed joins
$this->ensureMyTable();
$this->field_alias = $this->query->addField($this->tableAlias, $this->realField);
}
ddev get ddev/ddev-redis
ddev restart
// settings.php
$settings['redis.connection']['host'] = 'redis';
$settings['redis.connection']['port'] = 6379;
$settings['cache']['default'] = 'cache.backend.redis';
// Don't cache these bins in Redis
$settings['cache']['bins']['form'] = 'cache.backend.database';
$settings['cache']['bins']['bootstrap'] = 'cache.backend.chainedfast';
$settings['cache']['bins']['discovery'] = 'cache.backend.chainedfast';
ddev redis-cli monitor # Watch all commands
ddev redis-cli info memory # Memory usage
ddev redis-cli dbsize # Number of keys
// settings.php — enable on production
$config['system.performance']['css']['preprocess'] = TRUE;
$config['system.performance']['js']['preprocess'] = TRUE;
# my_module.libraries.yml — attach only what's needed
my_library:
css:
theme:
css/my-styles.css: { minified: true }
js:
js/my-script.js: { minified: true }
dependencies:
- core/drupal
# Don't depend on jQuery unless required
// Attach library only where needed, not globally
$build['#attached']['library'][] = 'my_module/my_library';
ddev composer require drupal/webprofiler
ddev drush en webprofiler -y
Provides toolbar with:
# Enable Xdebug in DDEV
ddev xdebug on
# Generate cachegrind profiles
ddev exec php -d xdebug.mode=profile -d xdebug.output_dir=/tmp vendor/bin/drush cr
Analyze with KCachegrind, QCachegrind, or Webgrind.
# Check cache hit ratio
ddev drush cr && time ddev drush cr # Second run should be fast
# Count database queries on a page
ddev drush ws --severity=Notice | grep -c "query"
# Check for large config objects
ddev drush config:list | wc -l
Before deploying, verify:
loadMultiple())accessCheck() and range()#cache metadata\Drupal:: calls in hot paths (use DI)