Salsa Digital Drupal-Related Articles: Federal agency — new GovCMS website using cloned site and CivicTheme

Image removed.Overview  The agency’s challenge A large federal agency wanted a new website dedicated to a specific subset of its stakeholders. The agency was already using GovCMS for other sites, so wanted a new GovCMS Drupal 9 website.  Note : The agency can’t be named for security reasons.   The transformation Salsa cloned another new website we’d built for the agency using GovCMS and CivicTheme . The client then uploaded new content and images to the site. The combination of cloning the site and using CivicTheme saved our client considerable time and costs. The site was built in 2 months and for under $20k.

PreviousNext: Optimise Your Page Loads with Lazy Loading Javascript

How to optimise your progressively decoupled Drupal frontend with the new Intersection Observer API.

by rikki.bochow / 14 February 2023

Read on for front-end tips backed by code you can use! You can also watch the full video at the end of this post. 

What is Lazy Loading?

Lazy Loading isn’t a new concept; however, let's quickly recap what we know about it.

“Lazy loading is a strategy to identify resources as non-blocking (non-critical) and load these only when needed. It’s a way to shorten the length of the critical rendering path, which translates into reduced page load times.” Mozilla Developer Network.

Why is lazy loading significant?

Good performance offers many benefits.

How often have you given up and closed a web page because it took too long to load? Especially when you’re on your mobile or experiencing a poor connection. It’s easy to forget that not everyone has regular access to fast, reliable internet connections or devices.

There are plenty of benefits to lazy loading:

  • Improved initial page load times
  • Better perceived performance
  • Decreased data usage
  • Positive impact on SEO rankings
  • Higher conversion rates
  • Improved user experience

If you’d like to dive deeper into these metrics, check out Jake Archibald’s F1 series for before and after speed tests.

The basic principles of lazy loading

Stylesheets

Because stylesheet files are render-blocking, we need to determine what is critical or above-the-fold CSS and inline it. We then defer the rest with Javascript attribute swapping and use Drupal’s Library system to reduce unused CSS.

Javascript

We also need to determine our critical Javascript and consider inlining it. Definitely defer any JS that isn’t critical and load asynchronously where applicable. 

ES6 modules are deferred by default and supported by modern browsers, so can be combined with code splitting. Again, we can use Drupal’s Library system to reduce unused Javascript.

Media

Media can slow down pages too. That’s why the loading attribute is gaining support in both Drupal and browsers. 

Image removed. has the most comprehensive support, so you should avoid using Javascript for these and also avoid lazy loading images that are likely to be above the fold.

Always put height and width attributes to prevent layout shift and use the responsive images module.

But we want to lazy load more!

And with the Intersection Observer API, we can. 

So what is the Intersection Observer API?

“The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document’s viewport.” Mozilla Developer Network

Simply put, it means: “tell me when an element has scrolled into or out of view”.

This API isn’t new (having been around for roughly five years); however, the recent demise of Internet Explorer now means it has full browser support.

iframes

Let's take iframe in Firefox as an example. If you have a lot of iframes (because, let’s face it, sometimes you just need to) and you’d like to save your Firefox users from long pages loads, then you can use oembed_lazyload (which uses Intersection Observer).

Alternatively, you can write a very simple Intersection Observer to populate the iframe src attribute from the data-src value.

In the video below, I ran through a basic introduction to the Intersection Observer API. I used all the default settings and checked the isIntersecting property, swapping the attributes, and then Unobserving the iframe (so it didn’t trigger again when it scrolled into the viewport subsequent times).

// const lazyLoadIframe = iframe => { const obs = new IntersectionObserver(items => { items.forEach(({ isIntersecting }) => { if (isIntersecting) { iframe.src = iframe.dataset.src obs.unobserve(iframe) } }) }) obs.observe(iframe) } window.addEventListener('load', () => { document.querySelectorAll('iframe').forEach(iframe => lazyLoadiFrame(iframe)) })

Javascript applications

We can expand on this idea of deferring assets that are below the fold and think about our progressively or partially decoupled projects.

In the following example, we’ll imagine a Drupal site with complex javascript applications embedded here and there. The apps are written in React, Vue or even Vanilla JS; they fetch data from Drupal as a JSON file and load their CSS. There may also be multiple apps on a page.

If we load these apps, as usual, we’ll load everything, including dependencies (JSON, CSS etc.) on the initial page load, regardless of whether we defer or async the javascript. It’s not render-blocking, but users who don’t scroll down to see the App are still downloading it.

Instead, we can combine the Intersection Observer with a Dynamic Import and truly defer loading all the apps’ resources until the mounting element is in the user's viewport. 

In the below code example, the load() function is only called upon intersection, so none of the apps’ dependencies are requested until the container scrolls into the viewport, significantly decreasing the initial page load time.

React example;

const lazyLoadApp = ( container, componentPath, props = {}, callback = () => [] ) => { const load = async () => Promise.all([ import("react-dom"), import("react"), import(componentPath), ]).then(([ { render }, React, { default: Component } ]) => render(, container, callback) ) const obs = new IntersectionObserver(items => { items.forEach(({ isIntersecting }) => { if (isIntersecting) { load() obs.unobserve(container) } }) }) obs.observe(container) }

We use Promise.all to ensure all of our dependencies are met, and then we destructure what we need from those dependencies and render our app.

After this happens, we unobserve the container.

You can also adjust the load() function as needed, i.e. import Vue and createApp instead–whatever your setup requires. 

Example for Vue 3;

const load = async () => Promise.all([ import("vue"), import(componentPath), ]).then(([ { createApp }, { default: Component } ]) => { const app = createApp(Component, props) callback(app) app.mount(container) })

Example for React 18;

const load = async () => Promise.all([ import("react-dom/client"), import("react"), import(componentPath), ]).then(([ { createRoot }, React, { default: Component } ]) => { const root = createRoot(container) root.render() // callback function moves into Component. })

Then usage would be something like:

// window.addEventListener('load', () => { document.querySelectorAll('[data-app-example]').forEach(container => lazyLoadApp( container, './path-to/component.jsx', { title: container.dataset.title, id: container.id, }, () => container.setAttribute('data-mounted', true) )) })

Here's the breakdown;

  • pass in the container (div to render/mount to)
  • the path to a specific component
  • any props needed (maybe simple data attributes or drupalSettings)
  • even a callback function after mounting has occurred

Accessibility considerations

We need to remember that the WCAG have findability rules for hidden content. Adding a heading (maybe even a description) inside the container with a button that triggers the load function might help with this. They get replaced by the rendered app but are available for screen readers and keyboard navigation.

You’ll also need to consider the following: 

  • How important is the content in the JS app?
  • Is the content shown elsewhere, or can it be?
  • Is the app itself accessible?
  • What will happen if JS isn’t enabled?

UX considerations

The unmounted container is also a good use case for Skeleton User Interfaces. Start by giving the container a grey background with a rough height/width for the rendered app, then add a loading animation, and you’ll help reduce the “jump” of the suddenly rendered app whilst also improving the perceived performance. 

This approach is also a great way to prevent Layout Shift issues. Also, remember to notify the user if something has failed to load.

You can tweak the Intersection Observer’s settings to increase or decrease the point of intersection, allowing for sticky headers, for example.

What else can we do with the Intersection Observer?

Other use cases for the Intersection Observer include:

  • Scroll-spy type components that update sticky anchor navigation
  • Animations that only start once in the viewport or should stop once outside the viewport.
  • Infinite scrolling pagination
  • Pausing videos when scrolled passed
  • Bookmarking where an article has been read to

Let’s not forget that the post-Internet Explorer world is full of Observers, including:

  • Mutation Observer. For DOM changes, such as attributes or markup/content injection (i.e. knowing when one app has rendered).
  • Resize Observer. A more performant version of the window.resize event for element dimension changes.

These all follow the same Observe/Unobserve pattern, so once you learn one, you won’t be able to stop yourself from using them all!

Talking Drupal: Talking Drupal #386 - Drupal Vs Wordpress

Today we are talking about Drupal & Wordpress with Maciej Palmowski.

For show notes visit: www.talkingDrupal.com/386

Topics
  • What is Wordpress
  • Do you have Drupal experience
  • Pros of Drupal over Wordpress
  • Pros of Wordpress over Drupal
  • Selecting a CMS
  • What sites don’t work well with Wordpress
  • What sites don’t work well with Drupal
  • Headless in Wordpress
  • Will Wordpress use Symfony?
  • Who wins?
Resources Guests

Maciek Palmowski - maciekpalmowski.dev @palmiak_fp

Hosts

Nic Laflin - www.nLighteneddevelopment.com @nicxvan John Picozzi - www.epam.com @johnpicozzi Katherine Druckman - katherinedruckman.com @katherined

MOTW Correspondent

Martin Anderson-Clutz - @mandclu WordPress Migrate Supports migrating Wordpress exports into Drupal, including posts, pages, attachments, tags, and categories.

The Drop Times: Remembering Rachel Olivero

Four years have passed since Rachel Olivero left us. Drupal rever her by naming the current default frontend theme, 'Olivero.' Drupal is now WCAG compliant, and our added support for ATAG 2.0 proves that we live by her legacy. Drupal encourages the use of assistive technologies. It is all the more important for a person with vision disabilities. Accessibility, Diversity, and Inclusion are the cardinal ideals we follow, and Rachel was involved in all these areas. Her memorial in Drupal.org recalls that as a person who was blind, transgender, and a lesbian, Rachel understood a lot about the importance of diversity. She passed away on February 03, 2019. Let us keep on her vision forward, keeping Drupal open and accessible for everyone.

Last week, TheDropTimes (TDT) ran two interviews with the organizers of Florida DrupalCamp. AmyJune Hineline (volkswagenchick) emphasized the importance of accessibility in her interview, stating accessibility is not an option or an add-on; it should be a default. In the second interview, Adam Varn (hotsaucedesign) opines that the success of Olivero and Claro as modern, accessible themes shows that Drupal still has plenty to offer a themer interested in Drupal, and with the new Starterkit project coming to stabilization in Drupal 10, there will be even more tools.

Drupal 10 Development Cookbook got released last week, thanks to Matt Glaman, Kevin Quillen, and Justin Cornell. Drupal Association announced Rosa Ordinana and Lynne Capozzi joining as its new board members. As part of diversity and inclusion, the association is aligning with Black History Month. On Monday, 21 February 2021, at 10:00 am EST (15:00 hrs UTC), Joi Garrett, will introduce the new 'Black in Drupal' program.

Scroll further down for the rest of the stories from the past week.

Sincerely,
Sebin A. Jacob
Editor-in-Chief,
TheDropTimes

Matt Glaman: The Drupal 10 Development Cookbook is out!

The Drupal 10 Development Cookbook is officially out! Special thanks to Kevin Quillen for his amazing assistance in writing the book. And my good friend Justin Cornell as a technical reviewer. You can order the print or ebook on Amazon (affiliate link) or Packt! This is technically the 3rd edition of the book. The first edition came out with the Drupal 8.0 release, and the second was around Drupal 8.5.0. So this covers everything that came with Drupal 9 and was added for Drupal 10!

We have 450 pages and fourteen chapters with walkthroughs and breakdowns for development with Drupal 10.

mandclu: A Quick Take on Headless and Performance

A Quick Take on Headless and Performance Image Image removed.mandclu Fri, 02/10/2023 - 07:09 Body There are a number of great reasons to consider a headless architecture for a web project. I sometimes hear site speed listed as a primary motivation. Is a headless website guaranteed to be faster? Let's explore this idea. There are certainly many examples of fast headless websites online today. But there are, in fact, a lot of slow headless websites around as well. And according to Google and their Core Web Vitals reporting, a website using Drupal as its CMS is almost twice as likely to have a good score as one based on popular headless CMS options like Contentful or ContentStack. Is the above an apples to comparison? Of course not. But we can say with certainty that any site using a headless-only CMS has a headless front end, and that many of those identified as using Drupal do not. SiteMore