A few of the enhancements include improving performance with better CSS and Javascript aggregation, reducing the headache of writing new code, and paving the way forward with community initiatives to squash bugs and fix issues.
Views responsive grid
This feature is already available in Drupal 10.0.0, but it couldn’t be added to Drupal 9.5 due to Internet Explorer 11 support, so if you haven’t updated to Drupal 10, you won’t have seen it yet.
A responsive grid allows you to specify the maximum number of columns, the minimum grid cell width, and the gutter spacing.
When the grid cells resize to a point where they’re below the minimum width, the grid will reflow to have fewer columns.
Alternatively, the grid will expand to fit as many columns as permitted while keeping the grid width above the minimum value.
This saves time for developers and website owners by enabling them to configure a feature that previously required custom code or contributed modules in just a couple of minutes.
Better CSS and JavaScript aggregation
Drupal core has shipped with CSS and JavaScript aggregation for over a decade.
However, the implementation had a number of issues and pre-dated Drupal’s library API.
- Before, aggregates had to be built by the main page request.
This resulted in stampedes on cold caches since no page could be served until aggregates were built and individual pages could take hundreds of milliseconds to executant time. - There was no built-in JavaScript aggregation in the core.
In Drupal 10.1, completely rewritten aggregation generation logic solves both of these issues.
- Aggregates are now built by a dedicated route, with the main request only responsible for generating the aggregate URL based on libraries, theme, language, and grouping logic.
This change resolves the cold cache stampede as well as makes things more robust against race conditions - JavaScript minification is now provided in the core, using the very reliable Peast JavaScript AST parser.
This should massively reduce, if not eliminate, the need to install contributed modules to minify JavaScript.
Constructor property promotion
When writing new Drupal code, one of the most annoying things can be the amount of boilerplate required when defining a constructor.
Property declarations that are almost identical to @param documentation.
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The entity repository.
*
* @var \Drupal\Core\Entity\EntityRepositoryInterface
*/
protected $entityRepository;
/**
* The configuration factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The typed config manager.
*
* @var \Drupal\Core\Config\TypedConfigManagerInterface
*/
protected $typedConfigManager;
/**
* The active configuration storage.
*
* @var \Drupal\Core\Config\StorageInterface
*/
protected $activeStorage;
/**
* The event dispatcher.
*
* @var \Symfony\Contracts\EventDispatcher\EventDispatcherInterface
*/
protected $eventDispatcher;
/**
* The extension path resolver.
*
* @var \Drupal\Core\Extension\ExtensionPathResolver
*/
protected $extensionPathResolver;
/**
* Creates ConfigManager objects.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The configuration factory.
* @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config_manager
* The typed config manager.
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
* The string translation service.
* @param \Drupal\Core\Config\StorageInterface $active_storage
* The active configuration storage.
* @param \Symfony\Contracts\EventDispatcher\EventDispatcherInterface $event_dispatcher
* The event dispatcher.
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
* The entity repository.
* @param \Drupal\Core\Extension\ExtensionPathResolver $extension_path_resolver
* The extension path resolver.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, ConfigFactoryInterface $config_factory, TypedConfigManagerInterface $typed_config_manager, TranslationInterface $string_translation, StorageInterface $active_storage, EventDispatcherInterface $event_dispatcher, EntityRepositoryInterface $entity_repository, ExtensionPathResolver $extension_path_resolver) {
$this->entityTypeManager = $entity_type_manager;
$this->configFactory = $config_factory;
$this->typedConfigManager = $typed_config_manager;
$this->stringTranslation = $string_translation;
$this->activeStorage = $active_storage;
$this->eventDispatcher = $event_dispatcher;
$this->entityRepository = $entity_repository;
$this->extensionPathResolver = $extension_path_resolver;
}
Since Drupal 10 requires PHP 8.1, we can get rid of most of that boilerplate, so that exactly the same constructor looks like this instead:
/**
* Creates ConfigManager objects.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* The entity type manager.
* @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
* The configuration factory.
* @param \Drupal\Core\Config\TypedConfigManagerInterface $typedConfigManager
* The typed config manager.
* @param \Drupal\Core\StringTranslation\TranslationInterface $stringTranslation
* The string translation service.
* @param \Drupal\Core\Config\StorageInterface $activeStorage
* The active configuration storage.
* @param \Symfony\Contracts\EventDispatcher\EventDispatcherInterface $eventDispatcher
* The event dispatcher.
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entityRepository
* The entity repository.
* @param \Drupal\Core\Extension\ExtensionPathResolver $extensionPathResolver
* The extension path resolver.
*/
public function __construct(
protected EntityTypeManagerInterface $entityTypeManager,
protected ConfigFactoryInterface $configFactory,
protected TypedConfigManagerInterface $typedConfigManager,
protected TranslationInterface $stringTranslation,
protected StorageInterface $activeStorage,
protected EventDispatcherInterface $eventDispatcher,
protected EntityRepositoryInterface $entityRepository,
protected ExtensionPathResolver $extensionPathResolver,
) {}
Much more compact with the same amount of actual implementation. This has already been adopted for new code, there’s a bit more involved to apply it to existing code.