Talking Drupal: Talking Drupal #453 - Urban Institute

 Today we are talking about Urban Institute, What they do, and How they use Drupal with guest Josh Miller. We’ll also cover Access Unpublished as our module of the week.

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

Topics
  • Tell us how you got started with Drupal
  • What does Urban Institute do
  • What do you do at Urban Institute
    • Number of people on dev team
    • Number of sites
  • How does Urban Institute use Drupal
  • Are you using a custom upstream
  • How many sites on Drupal 7
  • Are you doing Page builders
  • What kind of front end tools do you use
  • What is the preferred local development tool
  • Why did Urban Institute choose Drupal
  • What is the hardest part of using Drupal at a large non profit
  • What is the most interesting interactive experience you have built for Urban Institute
Resources Guests

Josh Miller - joshmiller

Hosts

Nic Laflin - nLighteneddevelopment.com nicxvan John Picozzi - epam.com johnpicozzi Randy Fay - rfay

MOTW Correspondent
  • Martin Anderson-Clutz - mandclu.com mandclu
  • Brief description:
    • Have you ever wanted to get feedback on unpublished content from people who aren’t users on your Drupal site? There’s a module for that.
  • Module name/project name:
  • Brief history
    • How old: created in Feb 2011 by aberg, though recent releases are by Christian Fritsch (chr.fritsch) of Thunder
    • Versions available: 8.x-1.5
  • Maintainership
    • Security coverage
    • Test coverage
    • Number of open issues: 58 open issues, 17 of which are bugs against the current branch
  • Usage stats:
    • 8,638 sites
  • Module features and usage
    • Once installed, this module adds a new element to your unpublished entity forms, for generating links with a special hash value. When generating the link, you can choose how long the hash value can be used for access.
    • Within that form section, you can copy the access URL for any of your generated tokens, and then paste into an email or some kind of direct message.
    • You will need to set a permission for users to access content using the special access URLs, so if you want anyone with the URL to be allowed access, you’ll need to assign that permission to the Anonymous user role
    • The access lifetime can be anything from 1 day to unlimited (never expires), and you can set the default value in the settings form. That form also allows you to set the URL parameter that will be used for access, gives you options to modify the HTTP headers on the unpublished page, and has a check box you can use to delete all expired tokens.
    • Expired tokens will be deleted on cron run, and when you delete an entity any related tokens are also removed.
    • This use case of allowing review of unpublished content for people who aren’t users in the Drupal site is a request I hear on a regular (if infrequent) basis, so I’ve personally found this module really useful.
  • Necessary Patch: https://www.drupal.org/project/access_unpublished/issues/3421309
  • Not to be confused with https://www.drupal.org/project/preview_link
    • Preview link is missing the ability to set length of access.

Drupal Association blog: Pride Month 2024: Celebrating International Pride

To celebrate Pride Month 2024, the Drupal Association is sharing information to uplift international organizations that support the LGBTQ+ community and donating our proceeds of themed apparel from the Drupal Swag Shop to those organizations. Pride Month is celebrated in June each year to acknowledge the anniversary of the Stonewall Uprising (1969), which was a tipping point for the gay liberation movement and spurred the growth of LGBTQ+ support. The movement has since spread across the globe. Read more on the history of Pride Month.

The Drupal Association is guided by the values of open source, which have a strong history of inclusivity. Our focus is human-centric. We believe that the way forward is with collective responsibility, accountability, and care. As stated in the Open Web Manifesto, the open web thrives on inclusion: Everyone in the world, regardless of background, identity, wealth, or status, has a home on the open web. Inclusivity is one of Drupal’s core principles, making an open web possible. At the core of our beliefs is that every individual, regardless of sexual orientation, gender identity, or expression, has a place here and deserves to be supported.

This year, the Drupal Association will celebrate LGBTQ+ organizations from around the world who work in different sectors: jobs and training, legal advocacy, refugee support, and youth mental health. We invite you to learn more about each organization that we highlight. Then, we ask you, the Drupal Community, to vote for which organization will receive the proceeds from Drupal Pride swag raised during Pride Month in the Drupal Swag Shop.

Here are the organizations we will be celebrating during each week of the month:

  • Week 1: Micro Rainbow International Foundation is an organization that works globally to help LGBTQ+ people achieve their full potential in life and have equal access to employment, training, education, financial services, healthcare, housing, places of faith, and public places and services.

  • Week 2: Human Dignity Trust defends the human rights of LGBTQ+ people globally to challenge laws that persecute people on the basis of their sexual orientation and/or gender identity.

  • Week 3: Rainbow Railroad supports refugees, helping at-risk LGBTQ+ people get to safety worldwide. They’ve helped over 13,000 LGBTQ+ individuals find safety through emergency relocation, crisis response, cash assistance, and more.

  • Week 4: The Trevor Project provides resources for international LGBTQ+ youth, including a 24/7 helpline and a safe and secure social networking site for LGBTQ+ youth and their allies.

Follow the Drupal Association on Linkedin and X/Twitter as we celebrate each organization this month! 

You can shop now and throughout the month of June in the Drupal Swag Shop for Drupal Pride gear! At the end of the month, 100% of the Drupal Association’s profits from the sales of the Drupal Pride gear will be donated to the LGBTQ+ organization that receives the most votes. Shop now and spread the word with the community! 

When you’re ready, we invite you to vote for the organization for which you want to receive the donation.

We want to hear your Drupal Pride stories!

In addition to celebrating LGBTQ+ organizations worldwide, we want to hear the Drupal community’s stories! What does Drupal Pride mean to you? We want to hear why Pride is important to you. We invite you to share your story with us to be featured on the Drupal Association social media channels celebrating Pride Month 2024! 

We are looking for videos that are less than 30 seconds long, short quotes, or photos that we can share on social media to amplify your messages. To share your story, you can either upload it to this Google Drive folder or email it directly to christina@association.drupal.org. We look forward to seeing your submissions and celebrating Pride together!

Mario Hernandez: Automating your Drupal Front-end with ViteJS

Modern web development relies heavily on automation to stay productive, validate code, and perform repetitive tasks that could slow developers down. Front-end development in particular has evolved, and it can be a daunting task to configure effective automation. In this post, I'll try to walk you through basic automation for your Drupal theme, which uses Storybook as its design system.

Recently I worked on a large Drupal project that needed to migrate its design system from Patternlab to Storybook. I knew switching design systems also meant switching front-end build tools. The obvious choice seemed to be Webpack, but as I looked deeper into build tools, I discovered ViteJS.

Vite is considered the Next Generation Frontend Tooling, and when tested, we were extremely impressed not only with how fast Vite is, but also with its plugin's ecosystem and its community support. Vite is relatively new, but it is solid and very well maintained. Learn more about Vite.

The topics covered in this post can be broken down in two categories:

  1. Preparing the Front-end environment

  2. Automating the environment

NOTE: The project covered in this post does not use Single Directory Components nor the Storybook module.

1. Build the front-end environment with Vite & Storybook

In a previous post, I wrote in detail how to build a front-end environment with Vite and Storybook, I am going to spare you those details here but you can reference them from the original post.

  1. In your command line, navigate to the directory where you wish to build your environment. If you're building a new Drupal theme, navigate to your site's web/themes/custom/
  2. Run the following commands (Storybook should launch at the end):
npm create vite@latest storybook cd storybook npx storybook@latest init --type react

Fig. 1: The first command builds the Vite project, and the last one integrates Storybook into it.

Reviewing Vite's and Storybook's out of the box build scripts

Vite and Storybook ship with a handful of useful scripts. We may find some of them already do what we want or may only need minor tweaks to make them our own.

  • In your code editor, open package.json from the root of your newly built project.
  • Look in the scripts section and you should see something like this:
"scripts": { "dev": "vite", "build": "vite build", "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build" },

Fig. 2: Example of default Vite and Storybook scripts out of the box.

To run any of those scripts, prefix them with npm run. For example: npm run build, npm run lint, etc. Let's review the scripts.

  • dev: This is a Vite-specific command which runs the Vite app we just build for local development
  • build: This is the "do it all" command. Running npm run build on a project runs every task defined in the build configuration we will do later. CI/CD runners run this command to build your app for production.
  • lint: Will lint your JavaScript code inside .js or .jsx files.
  • preview: This is also another Vite-specific command which runs your app in preview mode.
  • storybook: This is the command you run to launch and keep Storybook running while you code.
  • build-storybook: To build a static version of Storybook to package it or share it, or to run it as a static version of your project.

Building your app for the first time

Getting a consistent environment

In front-end development, it is important everyone in your team use the same version of NodeJS while working in the same project. This ensures consistency in your project's behavior for everyone in your team. Differences in the node version your team uses can lead to inconsistencies when the project is built. One way to ensure your team is using the same node version when working in the same project, is by adding a .nvmrc file in the root of your project. This file specifies the node version your project uses. The node version is unique to each project, which means different projects can use different node versions.

  • In the root of your theme, create a file called .nvmrc (mind the dot)
  • Inside .nvmrc add the following: v20.14.0
  • Stop Storybook by pressing Ctrl + C in your keyboard
  • Build the app:
nvm install npm install npm run build

Fig. 3: Installs the node version defined in .nvmrc, then installs node packages, and finally builds the app.

NOTE: You need to have NVM installed in your system to execute nvm commands.
You only need to run nvm install once per project unless the node version changes. If you switch to a project that uses a different node version, when you return to this project, run nvm use to set your environment back to the right node version.

The output in the command line should look like this:

Image removed.

Fig. 4: Screenshot of files compiled by the build command.

By default, Vite names the compiled files by appending a random 8-character string to the original file name. This works fine for Vite apps, but for Drupal, the libraries we'll create expect for CSS and JS file names to stay consistent and not change. Let's change this default behavior.

  • First, install the glob extension. We'll use this shortly to import multiple CSS files with a single import statement.
npm i -D glob
  • Then, open vite.config.js in your code editor. This is Vite's main configuration file.
  • Add these two imports around line 3 or directly after the last import in the file
import path from 'path'; import { glob } from 'glob';
  • Still in vite.config.js, replace the export default... with the following snippet which adds new settings for file names:
export default defineConfig({ plugins: [ ], build: { emptyOutDir: true, outDir: 'dist', rollupOptions: { input: glob.sync(path.resolve(__dirname,'./src/**/*.{css,js}')), output: { assetFileNames: 'css/[name].css', entryFileNames: 'js/[name].js', }, }, }, })

Fig. 5: Build object to modify where files are compiled as well as their name preferences.

  • First we imported path and { glob }. path is part of Vite and glob was added by the extension we installed earlier.
  • Then we added a build configuration object in which we defined several settings:
    • emptyOutDir: When the build job runs, the dist directory will be emptied before the new compiled code is added.
    • outDir: Defines the App's output directory.
    • rollupOptions: This is Vite's system for bundling code and within it we can include neat configurations:
      • input: The directory where we want Vite to look for CSS and JS files. Here's where the path and glob imports we added earlier are being used. By using src/**/**/*.{css,js}, we are instructing Vite to look three levels deep into the src directory and find any file that ends with .css or .js.
      • output: The destination for where CSS and JS will be compiled into (dist/css and dist/js), respectively. And by setting assetFileNames: 'css/[name].css', and entryFileNames: 'css/[name].js', CSS and JS files will retain their original names.

Now if we run npm run build again, the output should be like this:

Image removed.

Fig. 6: Screenshot of compiled code using the original file names.

The random 8-character string is gone and notice that this time the build command is pulling more CSS files. Since we configured the input to go three levels deep, the src/stories directory was included as part of the input path.

2. Restructure the project

The out of the box Vite project structure is a good start for us. However, we need to make some adjustments so we can adopt the Atomic Design methodology. This is today's standards and will work well with our Component-driven Development workflow. At a high level, this is the current project structure:

> .storybook/ > dist/ > public/ > src/ |- stories/ package.json vite.config.js

Fig. 7: Basic structure of a Vite project listing only the most important parts.

  • > .storybook is the main location for Storybook's configuration.
  • > dist is where all compiled code is copied into and where the production app looks for all code.
  • > public is where we can store images and other static assets we need to reference from our site. Equivalent to Drupal's /sites/default/files/.
  • > src is the directory we work out of. We will update the structure of this directory next.
  • package.json tracks all the different node packages we install for our app as well as the scripts we can run in our app.
  • vite.config.js is Vite's main configuration file. This is probably where we will spend most of our time.

Adopting the Atomic Design methodology

The Atomic Design methodology was first introduced by Brad Frost a little over ten years ago. Since then it has become the standard for building web projects. Our environment needs updating to reflect the structure expected by this methodology.

  • First stop Storybook from running by pressing Ctrl + C in your keyboard.
  • Next, inside src, create these directories: base, components, and utilities.
  • Inside components, create these directories: 01-atoms, 02-molecules, 03-organisms, 04-layouts, and 05-pages.
  • While we're at it, delete the stories directory inside src, since we won't be using it.
NOTE: You don't need to use the same nomenclature as what Atomic Design suggests. I am using it here for simplicity.

Update Storybook's stories with new paths

Since the project structure has changed, we need to make Storybook aware of these changes:

  • Open .storybook/main.js in your code editor
  • Update the stories: [] array as follows:
stories: [ "../src/components/**/*.mdx", "../src/components/**/*.stories.@(js|jsx|mjs|ts|tsx)", ],

Fig. 8: Updating stories' path after project restructure.

The Stories array above is where we tell Storybook where to find our stories and stories docs, if any. In Storybook, stories are the components and their variations.

Add pre-built components

As our environment grows, we will add components inside the new directories, but for the purpose of testing our environment's automation, I have created demo components.

  • Download demo components (button, title, card), from src/components/, and save them all in their content part directories in your project.
  • Feel free to add any other components you may have built yourself. We'll come back to the components shortly.

3. Configure TwigJS

Before we can see the newly added components, we need to configure Storybook to understands the Twig and YML code we are about to introduce within the demo components. To do this we need to install several node packages.

  • In your command line run:
npm i -D vite-plugin-twig-drupal @modyfi/vite-plugin-yaml twig twig-drupal-filters html-react-parser
  • Next, update vite.config.js with the following configuration. Add the snippet below at around line 5:
import twig from 'vite-plugin-twig-drupal'; import yml from '@modyfi/vite-plugin-yaml'; import { join } from 'node:path';

Fig. 9: TwigJS related packages and Drupal filters function.

The configuration above is critical for Storybook to understand the code in our components:

  • vite-plugin-twig-drupal, is the main TwigJS extension for our project.
  • Added two new imports which are used by Storybook to understand Twig:
    • vite-plugin-twig-drupal handles transforming Twig files into JavaScript functions.
    • @modyfi/vite-plugin-yaml let's us pass data and variables through YML to our Twig components.

Creating Twig namespaces

  • Still in vite.config.js, add the twig and yml() plugins to add Twig namespaces for Storybook.
plugins: [ twig({ namespaces: { atoms: join(__dirname, './src/components/01-atoms'), molecules: join(__dirname, './src/components/02-molecules'), organisms: join(__dirname, './src/components/03-organisms'), layouts: join(__dirname, './src/components/04-layouts'), pages: join(__dirname, './src/components/05-pages'), }, }), yml(), ],

Fig. 10: Twig namespaces reflecting project restructure.

Since we removed the react() function by using the snippet above, we can remove import react from '@vitejs/plugin-react' from the imports list as is no longer needed.

  • Finally, since we updated our project structure earlier, let's update the rollupOptions' input path within the Twig build object configuration:
build: { emptyOutDir: true, outDir: 'dist', rollupOptions: { input: glob.sync(path.resolve(__dirname,'./src/components/**/*.{css,js}')), output: { assetFileNames: 'css/[name].css', entryFileNames: 'js/[name].js', }, }, },

Fig. 11: Twig plugin with updated input path.

With all the configuration updates we just made, we need to rebuild the project for all the changes to take effect. Run the following commands:

npm run build npm run storybook

The components are available but as you can see, they are not styled even though each component contains a CSS stylesheet in its directory. The reason is Storybook has not been configured to find the component's CSS. We'll address this shortly.

4. Configure postCSS

What is PostCSS? It is a JavaScript tool or transpiler that turns a special PostCSS plugin syntax into Vanilla CSS.

As we start interacting with CSS, we need to install several node packages to enable functionality we would not have otherwise. Native CSS has come a long way to the point that I no longer use Sass as a CSS preprocessor.

  • Stop Storybook by pressing Ctrl + C in your keyboard
  • In your command line run this command:
npm i -D postcss postcss-import postcss-import-ext-glob postcss-nested postcss-preset-env
  • At the root of your theme, create a new file called postcss.config.js, and in it, add the following:
import postcssImport from 'postcss-import'; import postcssImportExtGlob from 'postcss-import-ext-glob'; import postcssNested from 'postcss-nested'; import postcssPresetEnv from 'postcss-preset-env'; export default { plugins: [ postcssImportExtGlob(), postcssImport(), postcssNested(), postcssPresetEnv({ stage: 4, }), ], };

Fig. 12: Base configuration for postCSS.

One cool thing about Vite is that it comes with postCSS functionality built in. The only requirement is that you have a postcss.config.js file in the project's root. Notice how we are not doing much configuration for those plugins except for defining them. Let's review the code above:

  • postcss-import the base for importing CSS stylesheets.
  • postcss-import-ext-glob to do bulk @import of all CSS content in a directory.
  • postcss-nested to unwrap nested rules to make its syntax closer to Sass.
  • postcss-preset-env defines the CSS browser support level we need. Stage 4 means we want the "web standards" level of support.

5. CSS and JavaScript configuration

The goal here is to ensure that every time a new CSS stylesheet or JS file is added to the project, Storybook will automatically be aware and begin consuming their code.

NOTE: This workflow is only for Storybook. In Drupal we will use Drupal libraries in which we will include any CSS and JS required for each component.

There are two types of styles to be configured in most project, global styles which apply site-wide, and components styles which are unique to each component added to the project.

Global styles

  • Inside src/base, add two stylesheets: reset.css and base.css.
  • Copy and paste the styles for reset.css and base.css.
  • Inside src/utilities create utilities.css and in it paste these styles.
  • Inside src/, create a new stylesheet called styles.css.
  • Inside styles.css, add the following imports:
@import './base/reset.css'; @import './base/base.css'; @import './utilities/utilities.css';

Fig. 13: Imports to gather all global styles.

The order in which we have imported our stylesheets is important as the cascading order in which they load makes a difference. We start from reset to base, to utilities.

  • reset.css: A reset stylesheet (or CSS reset) is a collection of CSS rules used to clear the browser's default formatting of HTML elements, removing potential inconsistencies between different browsers before any of our styles are applied.
  • base.css: CSS Base applies a style foundation for HTML elements that is consistent for baseline styles such as typography, branding and colors, font-sizes, etc.
  • utilities.css: Are a collection of pre-defined CSS rules we can apply to any HTML element. Rules such as variables for colors, font size, font color, as well as margin, sizes, z-index, animations, etc.

Component styles

Before our components can be styled with their unique and individual styles, we need to make sure all our global styles are loaded so the components can inherit all the base/global styles.

  • Inside src/components create a new stylesheet, components.css. This is where we are going to gather all components styles.
  • Inside components.css add glob imports for each of the component's categories:
@import-glob './01-atoms/**/*.css'; @import-glob './02-molecules/**/*.css';

Fig. 14: Glob import for all components of all categories.

NOTE: Since we only have Atoms and Molecules to work with, we are omitting imports for 03-organisms, 04-layouts, 05-pages. Feel free to add them if you have that kind of components.

Updating Storybook's Preview

There are several ways in which we can make Storybook aware of our styles and javascript. We could import each component's stylesheet and javascript into each *.stories.js file, but this could result in some components with multiple sub-components having several CSS and JS imports. In addition, this is not an automated system which means we need to manually do imports as they become available. The approach we are going to take is importing the stylesheets we created above into Storybook's preview system. This provides a couple of advantages:

  • The component's *.stories.js files are clean without any css imports as all CSS will already be available to Storybook.
  • As we add new components with individual stylesheets, these stylesheets will automatically be recognized by Storybook.

Remember, the order in which we import the styles makes a difference. We want all global and base styles to be imported first, before we import component styles.

  • In .storybook/preview.js add these imports at the top of the page around line 2.
import Twig from 'twig'; import drupalFilters from 'twig-drupal-filters'; import '../src/styles.css'; /* Contains reset, base, and utilities styles. */ import '../src/components/components.css'; /* Contains all components CSS. */ function setupFilters(twig) { twig.cache(); drupalFilters(twig); return twig; } setupFilters(Twig);

Fig. 15: Importing all styles, global and components.

In addition to importing two new extensions: twig and twig-drupal-filters, we setup a setupFilters function for Storybook to read Drupal filters we may use in our components. We are also importing two of the stylesheets we created earlier:

  • styles.css contains all the CSS code from reset.css, base.css, and utilities.css (in that order)
  • components.css contains all the CSS from all components. As new components are added and they have their own stylesheets, they will automatically be included in this import.
IMPORTANT: For Storybook to immediately display changes you make in your CSS, the imports above need to be from the src directory and not dist. I learned this the hard way.

JavaScript compiling

On a typical project, you will find that the majority of your components don't use JavaScript, and for this reason, we don't need such an elaborate system for JS code. Importing the JS files in the component's *.stories.js should work just fine. Since the demo components dont use JS, I have commented near the top of card.stories.js how the component's JS file would be imported if JS was needed.

If the need for a more automated JavaScript processing workflow arose, we could easily repeat the same CSS workflow but for JS.

Build the project again

Now that our system for CSS and JS is in place, let's build the project to ensure everything is working as we expect it.

npm run build npm run storybook

You may notice that now the components in Storybook look styled. This tells us our new system is working as expected. However, the Card component, if you used the demo components, is missing an image. We will address this issue in the next section.

This concludes the preparation part of this post. The remaining part will focus on creating automation tasks for compiling, minifying and linting code, copying static assets such as images, and finally, watching for code changes as we code.

6. Copying images and other assets

Copying static assets like images, icons, JS, and other files from src into dist is a common practice in front-end projects. Vite comes with built-in functionality to do this. Your assets need to be placed in the public directory and Vite will automatically copy them on build. However, sometimes we may have those assets alongside our components or other directories within our project.

In Vite, there are many ways to accomplish any task, in this case, we will be using a nice plugin called vite-plugin-static-copy. Let's set it up.

  • If Storybook is running, kill it with Ctrl + C in your keyboard
  • Next, install the extension by running:
npm i -D vite-plugin-static-copy
  • Next, right after all the existing imports in vite.config.js, import one more extension:
import { viteStaticCopy } from 'vite-plugin-static-copy';
  • Lastly, still in vite.config.js, add the viteStaticCopy function configuration inside the plugins:[] array:
viteStaticCopy({ targets: [ { src: './src/components/**/*.{png,jpg,jpeg,svg,webp,mp4}', dest: 'images', }], }),

Fig. 16: Adds tasks for copying JavaScript and Images from src to dist.

The viteStaticCopy function we added allows us to copy any type of static assets anywhere within your project. We added a target array in which we included src and dest for the images we want copied. Every time we run npm run build, any images inside any of the components, will be copied into dist/images.
If you need to copy other static assets, simply create new targets for each.

  • Build the project again:
npm run build npm run storybook

The missing image for the Card component should now be visible. Pretty sweet! 🍰

7. The Watch task

A watch task makes it possible for developers to see the changes they are making as they code, and without being interrupted by running commands. Depending on your configuration, a watch task watches for any changes you make to CSS, JavaScript and other file types, and upon saving those changes, code is automatically compiled, and a Hard Module Reload (HMR) is evoked, making the changes visible in Storybook.

Although there are extensions to create watch tasks, we will stick with Storybook's out of the box watch functionality because it does everything we need. In fact, I have used this very approach on a project that supports over one hundred sites.

I actually learned this the hard way, I originally was importing the key stylesheets in .storybook/preview.js using the files from dist. This works to an extend because the code is compiled upon changes, but Storybook is not aware of the changes unless we restart Storybook. I spent hours debugging this issue and tried so many other options, but at the end, the simple solution was to import CSS and JS into Storybook's preview using the source files. For example, if you look in .storybook/preview.js, you will see we are importing two CSS files which contain all of the CSS code our project needs:

import '../src/styles.css'; import '../src/components/components.css';

Fig. 17: Importing source assets into Storybook's preview.

Importing source CSS or JS files into Storybook's preview allows Storybook to become aware immediately of any code changes.

The same, or kind of the same works for JavaScript. However, the difference is that for JS, we import the JS file in the component's *.stories.js, which in turn has the same effect as what we've done above for CSS. The reason for this is that typically not every component we build needs JS.

A real watch task

Currently we are running npm run storybook as a watch task. Nothing wrong with this. However, to keep up with standards and best practices, we could rename the storybook command, watch, so we can run npm run watch. Something to consider.

You could also make a copy of the storybook command and name it watch and add additional commands you wish to run with watch, while leaving the original storybook command intact. Choices, choices.

8. Linting CSS and JavaScript

Our workflow is coming along nicely. There are many other things we can do but for now, we will end with one last task: CSS and JS linting.

  • Install the required packages. There are several of them.
npm i -D eslint stylelint vite-plugin-checker stylelint-config-standard stylelint-order stylelint-selector-pseudo-class-lvhfa
  • Next, after the last import in vite.config.js, add one more:
import checker from 'vite-plugin-checker';
  • Then, let's add one more plugin in the plugins:[] array:
checker({ eslint: { lintCommand: 'eslint "./src/components/**/*.{js,jsx}"', }, stylelint: { lintCommand: 'stylelint "./src/components/**/*.css"', }, }),

Fig. 18: Checks for linting CSS and JavaScript.

So we can execute the above checks on demand, we can add them as commands to our app.

  • In package.json, within the scripts section, add the following commands:
"eslint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", "stylelint": "stylelint './src/components/**/*.css'",

Fig. 19: Two new npm commands to lint CSS and JavaScript.

  • We installed a series of packages related to ESLint and Stylelint.
  • vite-plugin-checker is a plugin that can run TypeScript, VLS, vue-tsc, ESLint, and Stylelint in worker thread.
  • We imported vite-plugin-checker and created a new plugin with two checks, one for ESLint and the other for Stylelint.
  • By default, the new checks will run when we execute npm run build, but we also added them as individual commands so we can run them on demand.

Configure rules for ESLint and Stylelint

Both ESLint and Stylelint use configuration files where we can configure the various rules we want to enforce when writing code. The files they use are eslint.config.js and .stylelintrc.yml respectively. For the purpose of this post, we are only going to add the .stylelintrc.yml in which we have defined basic CSS linting rules.

  • In the root of your theme, create a new file called .stylelintrc.yml (mind the dot)
  • Inside .stylelintrc.yml, add the following code:
extends: - stylelint-config-standard plugins: - stylelint-order - stylelint-selector-pseudo-class-lvhfa ignoreFiles: - './dist/**' rules: at-rule-no-unknown: null alpha-value-notation: number color-function-notation: null declaration-empty-line-before: never declaration-block-no-redundant-longhand-properties: null hue-degree-notation: number import-notation: string no-descending-specificity: null no-duplicate-selectors: true order/order: - - type: at-rule hasBlock: false - custom-properties - declarations - unspecified: ignore disableFix: true order/properties-alphabetical-order: error plugin/selector-pseudo-class-lvhfa: true property-no-vendor-prefix: null selector-class-pattern: null value-keyword-case: - lower - camelCaseSvgKeywords: true ignoreProperties: - /^--font/

Fig. 20: Basic CSS Stylelint rules.

The CSS rules above are only a starting point, but should be able to check for the most common CSS errors.

Test the rules we've defined by running either npm run build or npm run stylelint. Either command will alert you of a couple of errors our current code contains. This tells us the linting process is working as expected. You could test JS linting by creating a dummy JS file inside a component and writing bad JS in it.

9. One last thing

It goes without saying that we need to add storybook.info.yml and storybook.libraries.yml files for this to be a true Drupal theme. In addition, we need to create the templates directory somewhere within our theme.

storybook.info.yml

The same way we did for Storybook, we need to create namespaces for Drupal. This requires the Components module and storybook.info.yml configuration is like this:

components: namespaces: atoms: - src/components/01-atoms molecules: - src/components/02-molecules organisms: - src/components/03-organisms layouts: - src/components/04-layouts pages: - src/components/05-pages templates: - src/templates

Fig. 21: Drupal namespaces for nesting components.

storybook.libraries.yml

The recommended method for adding CSS and JS to components or a theme in Drupal is by using Drupal libraries. In our project we would create a library for each component in which we will include any CSS or JS the component needs. In addition, we need to create a global library which includes all the global and utilities styles. Here are examples of libraries we can add in storybook.libraries.yml.

global: version: VERSION css: base: dist/css/reset.css: {} dist/css/base.css: {} dist/css/utilities.css: {} button: css: component: dist/css/button.css: {} card: css: component: dist/css/card.css: {} title: css: component: dist/css/title.css: {}

Fig. 22: Drupal libraries for global styles and component's styles.

/templates

Drupal's templates' directory can be created anywhere within the theme. I typically like to create it inside the src directory. Go ahead and create it now.

  • Inside storybook.info.yml, add a new Twig namespace for the templates directory. See example above. Update your path accordingly based on where you created your templates directory.

P.S: When the Vite project was originally created at the begining of the post, Vite created files such as App.css, App.js, main.js, and index.html. All these files are in the root of the project and can be deleted. It won't affect any of the work we've done, but Vite will no longer run on its own, which we don't need it to anyway.

In closing

I realize this is a very long post, but there is really no way around it when covering these many topics in a single post. I hope you found the content useful and can apply it to your next Drupal project. There are different ways to do what I've covered in this post, and I challenge you to find better and more efficient ways. For now, thanks for visiting.

Download the theme

A full version of the Drupal theme built with this post can be downloaded.

Download the theme

Make sure you are using the theme branch from the repo.

Wim Leers: XB week 2: outlines emerging

Experience Builder (XB) must be able to render single directory components (SDC) … but really any component. Furthermore, to achieve the compromiseless UX we want, we’ll need both client-side and server-side rendering (to avoid network latency): isomorphic rendering. So on Monday May 20, Ben “bnjmnm”, Mateu “e0ipso”, Lee “larowlan”, Théodore “nod_”, Pierre “pdureau” and Tim met in a truly global meeting (from Lee’s Australia to Kris’ U.S. West Coast), with very interesting conclusions.
These are not current concerns for XB, but they will eventually be — this was early alignment to avoid wasting time.

Missed a prior week? See all posts tagged Experience Builder.

Goal: make it possible to follow high-level progress by reading ~5 minutes/week. I hope this empowers more people to contribute when their unique skills can best be put to use!

For more detail, join the #experience-builder Slack channel. Check out the pinned items at the top!

On the code front, Alex Pott (who initially proposed a different repository structure in #3446374, see last week’s post) nudged XB in a better direction: over the weekend, he provided an MR to reuse core’s PHPCS rules and +1’d the structure we settled on. I finished & merged what he started and am grateful for the result :)

On Tuesday, front-end lead Jesse’s MR to carve rough outlines of the UI (no premature detail while awaiting more detailed wireframes and interaction design) was merged, and introduced the Radix UI component library that Lauri recommended.

Image removed. Try it yourself locally if you like, but there’s not much you can do yet. See Jesse’s Slack message with more nuance.
Install the 0.x branch — the “Experience Builder PoC” toolbar item takes you there!

SDC is a foundation of XB, and while SDC recently left the experimental phase in Drupal core, it is itself still evolving. An example is #3390712, where work is happening to introduce the concept of component variants. On Wednesday, e0ipso, Christian “penyaskito” and pdureau started pushing that forward.

That same day, I pushed the commit that introduced a new FieldType plugin that actually implements Alex “effulgentsia” Bronstein’s proposed data model in #3440578.
An interesting suggestion on the proposal came from Matt “mglaman” Glaman: to implement this as a single field with 2 properties plus 1 computed property for the combined result … which matched my thinking exactly! I implemented it on Friday. More work to be done next week to get it to a mergeable state, and much more beyond that (nested component trees, (a)symmetric translations, easy querying and hence easy updates …)

From the flurry of activity above, a few outlines start to merge:

  • with squinting eyes: the silhouette of a UI
  • similarly: the data model as envisioned months ago by effulgentsia
  • things happening outside XB that are relevant to it, with people not just from Acquia, Lullabot and PreviousNext, but the beginning of far wider involvement 1globe-spanning even!

Which seamlessly brings us to the next highlight of the week: the very first asynchronous XB meeting in Drupal Slack, organized by Griffyn “griffynh” Heels on Thursday. After 24 hours 2, the discussion gets archived in a d.o issue (#3449517).
This first meeting had 24 participants (with <150 people in the #experience-builder channel: 1 in 6!), I’d say this was a success :)
One pattern stood out: people are eager to contribute, but don’t know how yet. The honest answer is: we’re figuring that out — there is a list of product requirements, a codebase of <1 week old targeting those requirements and Lauri’s concept wireframes from September 2023. Contributors are welcome already, and can have a huge influence on the direction and shape of XB, but at this time need to be comfortable with helping to make things more concrete.

At the end of the week, I met with pdureau 3, talking about the UI Suite Initiative he’s been pushing for years now. Deeply integrated design system support in XB is crucial per Lauri’s research, and that’s exactly where the people behind the UI Suite initiative have gained a lot of expertise — and a working codebase that has ~20 frequent contributors and ~80 contributors over the past year! UI Suite explicitly supports for the various artifact types that design systems consists of, and XB will need to support these too. As the tech lead for XB but somebody who has never used design systems, it’s important for me to listen & learn. So I mostly listened.
The UI Suite ecosystem is currently transitioning to build on top of SDC. e0ipso and pdureau have been enthusiastically collaborating on this, and their enthusiasm is now positively visible in the XB Slack channel too! How exactly UI Suite will influence XB is not yet clear, but it likely will.

Goal for next week: connect conceptual dots that today exist only in the heads of people who’ve been in sufficient meetings with Lauri.

  1. Hence why I stopped stating the employer of each individual — I’m still linking each individual so it’s easy to find out the organization name. And actually, quite a few of the names in this week’s update are independent/freelancers! In the end, any collaboration is between individuals, not organizations, so going forward I will only mention individuals’ names. When a new organization gets involved, I’ll state that too, but individuals deserve their own recognition. Each first mention of an individual in a post will always be linked to their drupal.org profile. ↩︎

  2. To enable equal participation from any timezone. Which will be crucial, since Dries invited the entire community to help build XB and Starshot! ↩︎

  3. He lives ~1000 km from me, but he happened to be in Brussels that week, so we made the best of that opportunity :) ↩︎

The Drop Times: DrupalJam 2024: Exclusive Insights from Organizers Driving Community Growth

Prepare for DrupalJam 2024! Set to take place on June 12th at the Fabrique in Utrecht, this event marks its 20th edition, promising a day of exploration and learning. Attendees will have the opportunity to gain valuable insights from keynote speaker Dries Buytaert, the program lead of Drupal. Organized by a dedicated team of volunteers, including Bart Vreugdenhil, Carole Grootenboer, Mario Gerssen, Rolf van de Krol, and Jean-Paul Vosmeer, DrupalJam embodies the collaborative spirit of the Drupal community. Kazima Abbas, sub-editor at The Drop Times, brings you exclusive insights from the organizers into the event's schedule, speakers, and engagement opportunities.

LN Webworks: How To Migrate From Drupal 7 to Drupal 10

Image removed.

We know that Drupal 7 reaching the end of life on January 5, 2023. It means it will no longer receive security updates or support from the Drupal community. So organizations or individuals that use Drupal 7 should upgrade to the latest version of Drupal 10.

What are Drupal migrations?

In Drupal migrations content, data, and configurations are transferred from one Drupal site to another. Migrations are commonly used when we upgrade from Older versions of Drupal to newer versions of Drupal.

Steps Taken Before Starting The Migration

Here's a concise list of steps to take before starting a migration

Step 1: Drupal 7 Database

First, back up the database of the Drupal 7 site. This ensures that if any issues are encountered during the migration, you can restore the site and re-run the process.

Using below command

Export: mysqldump -u root -p database name > filename.sql

Golems GABB: The leading SEO principles for Drupal in 2024: Tips for Marketers

The leading SEO principles for Drupal in 2024: Tips for Marketers Editor Fri, 05/31/2024 - 12:08

Drupal SEO tips come in whenever you need to build a firm foundation amidst the never-ending digital marketing and search engine optimization tricks. The overall industrial volatility can't help but demand more well-thought-out and user-engaging domains.
Take a closer look at modern SEO principles for Drupal 2024 — from content sustainability to the overall website architecture's adaptability and scalability. They demonstrate the international craving for turning solutions for customers' pain points, AI-based technologies, and human authorship into the best buddies. What Drupal modules will align with your business's vertical and horizontal success channels? Check it out!

Salsa Digital: A guide to design systems and their benefits

Image removed.Why build a design system? Designing and building a new website is often costly and time-consuming. Designers come up with a visual masterpiece, and then frontend developers have to build it — which  can be easier said than done, especially if the developer is working in isolation and not taking into consideration how difficult it might be to actually build their designs.

Evolving Web: Evolving Web Wins Pantheon Award for Social Impact

Image removed.

We are thrilled to announce that Evolving Web has been honored with the Social Impact Award in the Inaugural Pantheon Partner Awards for our work on the Planned Parenthood Direct website

The winners were announced at the Pantheon Partner dinner, held during DrupalCon Portland on May 6, 2024. Congratulations to the other winners who took to the stage with us: 

  • Elevated Third – Partner of the Year Award
  • WebMD Ignite – Innovation Award
  • HoundER – Rookie of the Year Award
  • Forum One – Customer First Award
  • Danny Pfeiffer – Friends of Pantheon Partners Award

Pantheon’s Partner Awards recognize the outstanding contributions of digital agencies that drive positive change. We’re proud to be acknowledged for our role in the Planned Parenthood Direct project, which supports reproductive rights and enhancing access to reproductive and sexual healthcare. Our work on the project demonstrates our commitment to creating impact through user-centric digital experiences.

Image removed.

Image removed.

Image removed.

A Mission-Driven Collaboration

In the U.S., reproductive and sexual health care services vary from state to state. Planned Parenthood Direct (PPD) aims to provide trusted care from anywhere by offering “on-the-go” services. We collaborated with PPD to build a secure, mobile-first website on that informs users of available services in their state. The site also encourages users to download the PPD app, which they can use to order birth control.

Designing for Impact and Inclusion

Our team undertook the challenge of creating a highly informative, accessible website that appeals to a younger audience.

  • We created dedicated pages for each state, ensuring they’re easy for PPD to update and optimized for search engines.
  • We created a new visual brand identity that incorporates bold design principles for a youthful, reassuring, and non-stigmatizing user experience.
  • Our mobile-first approach ensured that the site meets the needs of an audience who prefer mobile devices.
  • We also followed accessibility best practices to ensure a user-friendly experience for all, including users with disabilities. 

Image removed.

Protecting Users with Exceptional Security

Security was a paramount concern, given the political climate surrounding reproductive rights. We ensured a highly secure online experience using a decoupled architecture with Next.js for the front-end and Drupal 10 for the back-end. Hosting on Pantheon added additional layers of security, including HTTPS certificates and DDoS protection.

Image removed.

Setting PPD Up For Success & Growth 

Our work on the Planned Parenthood Direct website included the development of 17 custom components and 14 content types in Layout Builder. This empowers PPD’s content editors to create flexible, engaging, and visually appealing layouts. The results is streamlined content creation and management, allowing PPD to maintain and grow their website effectively.

Image removed.

Outstanding Results & Continued Commitment

The new Planned Parenthood Direct website has been instrumental in continuing PPD’s mission to support human rights and ensure access to sexual and reproductive healthcare.

A big thank you to Pantheon for recognizing our efforts, and to Planned Parenthood Direct for trusting us with this important project. We’re honoured to have partnered with you both.

As we celebrate this award, we’re reminded of the importance of our work and the impact it has on communities. We look forward to future opportunities to make a difference.

Partner with us to turn your vision into a powerful digital experience that drives change. 

Image removed.

+ more awesome articles by Evolving Web