drupal

Mario Hernandez: Components variations in Storybook

One great way to extend your catalog of components is by creating components variations. Variations, in the context of component-driven development, refers to displaying your content in different ways. Variations of a component reduce the need of building new components as well as duplicate code.

In Storybook, variations are known as Stories. In this post I will be using variations and stories interchangeably.

The image below shows how different card stories or variations, can display the same content in many ways.

Image removed.

Fig. 1: Example of multiple variations of a Card component.

Principles of building components

Sometimes when building a new component, we can't anticipage how the website will evolve with time and therefore we build components the best way possible at the time of building them. As time goes by and requirements change, we realize that we could have done things differently had we known about the requirements changes. Variations of a component give you a chance to alter how something was built without having to change your entire environment of content architecture.

Some time ago I wrote about principles for building components. Rather than repeating myself, take a quick look at the article and comeback when you are done. You will find those principles not only apply to building new components, but also to building variations of components.

Building component variations in Storybook

In Storybook, all variations of a component are referred to as "Stories", hence the name Storybook. A story captures the rendered state of a UI component. Developers write multiple stories per component that describe all the “interesting” states/variations a component can support. Here's a visual that describes the official naming and hierarchy Storybook uses.

Image removed.

Fig. 2: Storybook's official naming convention and hierarchy.

The Card component

First off, I am going with the assumption that you already know how Storybook stories are created and that you have a Storybook instance running. If that's not the case, follow these instructions to get your Storybook environment up and running. You will need NodeJS 20+ and NVM installed on your system to follow along.

Next, let's look at the Card variations we will be creating in this post.

Image removed.

Fig. 3: Example of the different card variations we will build in this post.

The image above shows the Card stories or variations we will build. From top-left to right:

  • Default or Stacked
  • Light CTA
  • Small
  • No image
  • Horizontal

In the interest of time, I have a repo that already includes the base of the Card component so you can focus only on building the variations.

  1. Clone the repo which already contains a project to work with and the Card component.

    If you already have a working Storybook environment, copy the components directory (src/components), from the newly cloned repo, into your project.
  2. Switch to the variations branch by running git checkout variations

  3. Run the project as instructed in the README in the repo

Methods for creating stories

In this tutorial, we will use two methods for creating variations in Storybook:

  1. Doing all the work directly in card.stories.jsx to change fields values or hide/show fields, depending on the story requirements.
  2. Using additional *.yml files to assist with the same fields updates above.

We will be using the first method above for all stories except the Card horizontal. The original Card component was built with Twig, but for the variations we will be working exclusively in card.stories.jsx. The current version of the card story looks like this:

import parse from 'html-react-parser'; import card from './card.twig'; import data from './card.yml'; import './card.css'; const component = { title: 'Molecules/Card', render: (args) => parse(card(args)), }; export const Card = { name: 'Card stacked', args: { ...data }, }; export default component;

Let me explain the snippet above as this is the foundation for all the variations we will be creating.

  • First we do a series of imports to collect all the pieces needed to build components and stories:

    • import parse: This is a react plugin which allows us to parse the HTML in our stories into React code Storybook can understand.
    • import card: It imports all the code and logic inside our component's twig template.
    • import data: Pulls in all the data from the component's .yml file so we can use it as React args.
    • import './card.css': Imports all CSS styles so Storybook can displayed the styled components and stories. Inside card.css, we already have styles for each of the stories we will be building.
  • Next, we set a new configuration object called component, which will serve as the default instance of the card component. This is an arbitrary name and can be anything that makes sense to you.
    Inside the component object we have two properties: title and render.

    • The title property's value determines the location and name of the component within Storybook's hierarchy. In this example the Card component will be located under the Molecules folder. See Fig.2 above for details about the hierarchy.
    • The render property is what handles the rendering of the component by using the card and data objects we imported earlier, and combined together (Twig and YML), they render the full component.
  • Next, we create our first story by defining a new configuration object called Card, in which we pass a name (Card stacked), for the story and the data variable as args.

  • Finally, we export the component object as default, which is a React requirement.

If Storybook is running, you should see the new variation which will display the Card stacked. If you need to run Storybook for the first time, in your command line navigate to the storybook directory and run these commands:

IMPORTANT: You need NodeJS 20+ and NVM installed in your system. nvm install npm install npm run build npm run storybook

If all goes well, Storybook should be running showing the Card stacked story under the Molecules folder.

Preview of Card stacked

Image removed.

Fig. 4: Example of the Card stacked from which other variations will originate.

Card with light CTA

  • Inside card.stories.jsx, and directly after the closing of the Card object (around line 17), add the following object to create a new story:
export const CardLightCta = { ...Card, name: 'Card light CTA', args: { ...data, cta: { modifier: 'button--light', text: 'Try it now', url: 'https://mariohernandez.io', } }, };

Let's go over the snippet above:

  • We start by creating and exporting a new object called CardLightCta. This is a new story. This name is arbitrary but it should be unique for each story.
  • Next, we pass the default Card story (...Card), as a spread operator, so the new story inherits all attributes from the original card.
  • The name property allows for each story to have a unique name which will appear directly under the component name in Storybook's sidebar (see Fig. 2 at the top for details).
  • Finally, we open the args object where we will update some of the fields to achieve the desired variation:
    • We pass the ...data object as a spread operator to individually update the fields that need updating.
    • Since the only difference between this variation and the original card is that the CTA is light, we need to define the cta object and provide each of its properties with the appropriate values:
      • First as a modifier class we pass button--light. This is a predefined modifier class which will turn the CTA white.
      • Next, we type the text that will become the CTA's label, Try it now.
      • And finally, we pass a URL to the CTA.

Preview of Card with light CTA

Image removed.

Fig. 5: Example of a Card component with a light CTA.

Card small

This next story or variation is the small version of the card. The difference between this card and the original one is that this one has no CTA, and its size is ...well, small 🙂

Same as before, add the following snippet to card.stories.jsx directly after the closing of the card with light CTA story:

export const CardSmall = { ...Card, name: 'Card small', args: { ...data, modifier: 'card--small', cta: '', }, };

This story is very similar to the previous one from the updates needed point of view. As you can see, the only thing we are doing is passing card--small as a modifier class to the entire component, and since we don't need a button or CTA, we are defining the cta object but its value is empty which will suppress it from printing on the page. If you notice in card.twig, we use a conditional that checks if the cta object exists, otherwise don't print any of the markup starting with the footer tag.

Preview of small card

Image removed.

Fig. 6: Example of a small card.

Card with no image

  • You know the drill, inside card.stories.jsx, directly after the closing of the previous story, add the following snippet:
export const CardNoImage = { ...Card, name: 'Card no image', args: { ...data, modifier: 'card--no-image', image: '', }, };

Even more similar to the previous story, this variation only varies from the original story as follows:

  • We are passing a modifier class to the component, card--no-image.
  • Since we want no image, we define the image object but leave its value empty.

Preview of card without image

Image removed.

Fig. 6: Example of a card without image.

Card horizontal

The final variation is the Card horizontal. For all previous variations we have done all the changes inside card.stories.jsx, but for this one, we will resource to using an alternative *.yml file. Why you may ask, well, this variation requires a bit more changes and making all those changes inside the stories.jsx file may look a little too busy and not as easy to read the code. That's pretty much the only reason for me to use this method, to keep the code in my stories clean and more readable.

You may have noticed in the project you cloned; inside the card directory we have a file called card-horizontal.yml. This file is almost identical to the original card.yml as far as the fields in it. The only difference is that some of the fields have unique content or no content at all. Let's look at the file before starting.

--- modifier: 'card--horizontal' image: <img src="/card-square.jpg" alt="Palm trees near city buildings" /> title: level: 2 modifier: 'card__title' text: 'Step outside to the outdoors' url: 'https://mariohernandez.io' teaser: 'With spring in full bloom, the weather could not be better to take a walk outside and enjoy the beauty of nature.' cta: ''

  • The modifier field has a specific CSS class we will pass: card--horizontal. This class will allow us to change the layout of the card to be in horizontal direction.
  • The image field uses a different image altogether. The image has been cropped in square aspect ratio for better fitting of this variation.
  • Finally, the cta field is empty, meaning we don't want to print a button on this variation.

Maybe I exaggerated when I said that this variation has too many changes, but my point is that in cases when your stories do require a lot of changes, using a different yml file may help you keep your stories.jsx file a lot neater and cleaner.

  • The first step is one we haven't done before. Inside card.stories.jsx somewhere around line 5 (after the last import in the file), add the following import:
import dataHorizontal from './card-horizontal.yml';

  • Next, the way we've done before, inside card.stories.jsx add the following object directly after the closing of the last story:
export const CardHorizontal = { ...Card, name: 'Card horizontal', args: { ...dataHorizontal, }, };

  • First we imported a new data file called card-horizontal.yml and assigned the object name of dataHorizontal. By doing this, any changes we make inside card-horizontal.yml will be reflected in Storybook.
  • Lastly, we repeat the same process as the previous variations but this time, inside the args object, we pass the new object we created in the previous step (...dataHorizontal), rather than ...data.
  • That's it. Our story file is nice and clean. Since we handled all the fields updates in card-horizontal.yml, the .jsx file is simply consuming its data to achieve the desired variations.

Preview of horizontal card

Image removed.

Fig. 6: Example of a card in horizontal layout.

Now that we have covered both methods for creating variations, know that neither method is better than the other. The decision to use one over the other boils down to personal preferences and sometimes which makes the most sense to simplify the process.

End result

At the end of this process, your card.stories.jsx should look like this:

import parse from 'html-react-parser'; import card from './card.twig'; import data from './card.yml'; import dataHorizontal from './card-horizontal.yml'; import './card.css'; const component = { title: 'Molecules/Card', render: (args) => parse(card(args)), }; export const Card = { name: 'Card stacked', args: { ...data }, }; export const CardLightCta = { ...Card, name: 'Card light CTA', args: { ...data, cta: { modifier: 'button--light', text: 'Try it now', url: 'https://mariohernandez.io', } }, }; export const CardSmall = { ...Card, name: 'Card small', args: { ...data, modifier: 'card--small', cta: '', }, }; export const CardNoImage = { ...Card, name: 'Card no image', args: { ...data, modifier: 'card--no-image', image: '', }, }; export const CardHorizontal = { ...Card, name: 'Card horizontal', args: { ...dataHorizontal, }, }; export default component;

In closing

This only touches the surface of creating stories, but it is refreshing to know that no matter how complex your components may be, when it comes to having Storybook parse them, the React code in your stories is very minimum. Certainly, there are exceptions, but as I complete the migration of our large Drupal project with many components, some of which are pretty large and complex, we still were surprised how little React code was required of us to write because all the heavy lifting is being done by Storybook, with its contrib extensions, as well as Twig itself.

Spinning Code: Knowing When to Ask for Help

One of the skills everyone needs to have is asking for help. Whether that’s in our work, our education, or our personal lives, we all need help from time to time. We are focused on work here, but this same basic rules apply in all aspects of our lives.

The right time to ask for help is, like so many things, a balancing act. Struggling through a complex issue can be a great way to learn something new. But often we can short cut that learning by simply asking the right questions at the right time.

On the flip side, if we ask too early not only do we risk missing a chance to build deep understanding, we also risk frustrating colleagues by asking them to do our job.

One short cut for when you need to ask for help is if another team member asks if you have already asked. Generally, I want to have called for support before my PM suggests it. By then they are frustrated that I haven’t already solved whatever the issue is solo.

Signs You Might Need Help

Given my current role and skill set, I’m often the person who gets called when a project goes sideways. That means I see a lot of places where someone didn’t call for help until they were in crisis. While that’s going to happen to us all from time to time, it’s better to call for help when the problem is small. If you want until the project starts burning down around you, it’s way too late.

You might need help if:

  • You have absolutely no idea what to do next.
  • You are about to re-design a large portion of your project to get around a challenge.
  • You have spent more than a day pounding on a problem without success.
  • You are avoiding working on a task, because you don’t know how to get started.
  • You are about to use a mode/tool/technique that everyone says is a bad idea.
    • In Salesforce that can mean things like:
      • loading data in serial mode
      • setting batch size to 1
      • using view all data in your tests.
    • In Drupal that can mean things like:
      • hacking a module
      • loading data in the theme layer
      • writing raw SQL queries

What to do Before Asking for Help

As I said before, asking for help is a balance: you can wait too long, or you can ask too soon. The real trick is hitting the sweet spot.

There are several things you should always do before taking another person’s time.

  • Google It! I kinda can’t believe I have to say that, but not everyone bothers.
  • Make sure you can explain the question clearly. If you don’t know where you got stuck, how can I help you get unstuck? And thinking it through might make the answer obvious.
  • Develop a theory. When asking for help, it can be useful to pose a theory about an approach. Even if you’re wrong it may help me understand your thinking.
  • Try a few things. Experimenting with what’s going wrong can help you formulate your question, and may help me short cut my research if you have eliminated obvious issues.
  • Explain the problem to your dog, cat, rabbit, stuff animal, etc. As someone who spends time being a human rubber duck, I can often tell when someone tried to explain it once already.

Where/Who to Ask for Help

For me, the hardest part is knowing who to ask.

As a consultant I try to avoid asking questions in places clients may see it. Our clients pay for us to be experts, they do not want to see us asking questions in public – particularly if the question has a simple answer.

As a Salesforce MVP, one of my favorite perks is the MVP Slack channel, where we ask each other questions that run the full range of complexity. While access to a community that hard to access, and that advanced, is a privilege there are other ways to find similar groups like your local user group.

I love having a good internal network of people to ask for help. Most of the places I have worked at as a consultant have had some kind of information place to ask questions and help each other out. If you work in a consultancy find or create such a back channel.

If concerns about being seen by clients isn’t relevant to you, check out this list of 7 Salesforce Communities to Join recommended by Salesforce Ben.

Help Build a Helpful Community

The final thing to know about asking for help, is that it’s important to offer help as well. A good question can be valuable to someone else who has the same issue in the future. A good answer is helpful to both the person who asked the question and the person who looks again in the future.

But offering answers, even if not perfect answers, is a great way to learn and encourage others to seek help. Any time I post a question on Stack Exchange, I try to hunt around for one or two to answer as well. That both allows me to pay it forward, it also helps encourage the tone that people can be experts in one thing while still needing help in another.

Smart people need help, and should be comfortable asking for it.

The post Knowing When to Ask for Help appeared first on Spinning Code.

ImageX: Unlock the Incredible Diversity of Robust AI-Driven Workflows with the AI Interpolator Module in Drupal

Authored by Nadiia Nykolaichuk.

It seems like yesterday that people started cautiously embracing artificial intelligence with admiration, surprise, or even fear. Technology rushes forward, multiplying the number of potential ways to use AI on your website to streamline your workflows.

Promet Source: How Population Size Shapes CMS Choices in Government

Takeaway: Government CMS preferences evolve with population size, shifting from specialized proprietary solutions for smaller entities to enterprise-level, often open-source platforms for larger ones. This shift reflects the need for greater scalability, flexibility, and advanced features as government entities grow and face more complex digital demands. NEED A CMS THAT CAN GROW WITH YOU? TALK TO OUR TEAM  

The Drop Times: Gábor Hojtsy and Pamela Barone Share Their Perspectives on Starshot

Explore the transformative vision behind Drupal Starshot through the insights of Gábor Hojtsy and Pamela Barone. This ambitious initiative addresses Drupal's past criticisms by enhancing user experience and accessibility with innovative UI improvements and pre-packaged feature sets. Delve into the potential and challenges of Starshot and understand how the leadership team is steering Drupal towards a more user-friendly future.

joshics.in: The Biggest Challenges in Drupal 10 Migration and How to Overcome Them

The Biggest Challenges in Drupal 10 Migration and How to Overcome Them bhavinhjoshi Thu, 06/27/2024 - 15:34

Drupal 10

Welcome to the world of Drupal 10, a cutting-edge iteration of one of the most powerful and feature-rich content management systems (CMS) available today. Launched in December 2022, Drupal 10 builds on the strengths of its predecessors while offering a range of exciting new features and improvements.

But what makes Drupal 10 stand out? First and foremost, it comes packed with the latest innovations in technology, security, and design, ensuring your website meets the modern-day demands of online users.

One of the most significant advantages of Drupal 10 over previous versions is its improved performance. Drupal 10 is faster and more efficient, providing an enhanced user experience which can lead to higher user engagement, lower bounce rates, and ultimately, increased conversions.

Drupal 10 also provides better security with its automatic updates feature, without relying on third-party plugins. This means you can rest easy knowing your website is always up-to-date and protected against potential cyber threats.

Furthermore, Drupal 10 comes with a new administrative theme, Olivero, that is more accessible and user-friendly. This makes it easier for website administrators to manage and edit content.

Inclusivity is also a major focus in Drupal 10. The CMS is designed to be more accessible, addressing the needs of users with disabilities and making the internet a more inclusive space for everyone.

Migrating to Drupal 10 may present some challenges, but the benefits far outweigh the hurdles. In this post, we will explore some of these challenges and provide practical solutions to ease the migration process. So, let's get started.

 

The Challenge of Deprecated Modules

One of the key challenges you might face when migrating to Drupal 10 is dealing with deprecated modules. “Deprecated” in this sense means that these modules are no longer recommended for use and are slated for removal in future versions of Drupal.

In previous versions of Drupal, you may have installed certain modules to extend the functionality of your site. These modules could range from image sliders and SEO tools, to custom field types and formatting options. However, since Drupal 10 is a step forward in terms of technology and usability, some of these modules might not be compatible with the new version.

When these deprecated modules are not supported by Drupal 10, they can cause disruption to the functionality of your website during the migration process. It's as if you're trying to fit a square peg into a round hole. The two are simply not compatible, and forcing them together won't work.

For example, you may find that a custom field type provided by a deprecated module no longer works in Drupal 10. This could lead to data loss, or perhaps certain sections of your website not displaying correctly. If your website heavily relies on such deprecated modules, this could potentially cause significant disruption to your site's functionality and user experience.

 

The Solution: Identifying and Replacing Deprecated Modules

Addressing the issue of deprecated modules requires a two-step process: identifying them and then replacing them with suitable alternatives in Drupal 10.

Identifying Deprecated Modules

The first step is to identify which modules on your site are deprecated. Drupal makes this process relatively straightforward with the use of the Upgrade Status module. This module provides a comprehensive report of all the deprecated code that your site is using, including modules.

To use the Upgrade Status module, you simply need to install it on your Drupal site and run a scan. The module will produce a list of deprecated modules you're currently using, making it easy for you to see what needs changing.

Replacing Deprecated Modules

Once you've identified the deprecated modules, the next step is to find suitable replacements.

Start by researching if there are updated versions of these modules that are compatible with Drupal 10. Module maintainers often release updated versions for new Drupal releases. You can usually find this information on the module's page on the Drupal website.

If a deprecated module doesn't have an updated version, you'll need to find an alternative module that offers similar functionality. The Drupal community is a good place to start your search. You can also ask for recommendations from other Drupal users. It's likely that others have faced a similar issue and can recommend a suitable module.

In some cases, you might find that the functions provided by a deprecated module have been incorporated into Drupal 10's core. In this case, you simply need to enable the corresponding functionality in Drupal 10.

Remember, always test new modules on a development version of your site before installing them on your live site. This way, you can ensure that the new module works correctly and doesn't cause any issues.

While dealing with deprecated modules can be a bit of a headache, it can also be an opportunity to streamline your site and improve its functionality.

 

The Challenge of Custom Code

If you've been operating a Drupal site for some time, it's likely that you or your development team have written custom code to tailor the website to your specific needs. This custom code could include anything from unique themes to specific functionalities that are critical to your website's operation. While this helps make your site uniquely yours, it can pose challenges during the migration process to Drupal 10.

Primarily, some of your custom code may not be compatible with Drupal 10 due to the differences in code requirements and standards between different Drupal versions. Your custom code may be using functions or methods that are deprecated in Drupal 10, or the architecture of Drupal 10 may simply not support your custom code.

This incompatibility can lead to errors during your site's migration to Drupal 10, causing certain functionalities to break or not function as intended. In worst-case scenarios, incompatible custom code can even make your website inaccessible. This can lead to a poor user experience, potentially causing lost audience engagement or revenue.

The challenge posed by custom code, therefore, is twofold: you need to identify the custom code that's causing issues, and then update or rewrite this code to be compatible with Drupal 10. This process can be time-consuming and complex, requiring a deep understanding of Drupal's coding requirements and standards.

 

The Solution: Identifying and Refactoring Custom Code

Managing custom code for a Drupal 10 migration can seem daunting, but with the right approach, it doesn't have to be. Here's how to go about it:

Identifying Problematic Custom Code

Much like identifying deprecated modules, the first step is to identify which parts of your custom code may be problematic in Drupal 10. The Upgrade Status module comes in handy here as well. Beyond just identifying deprecated modules, this tool can also scan your custom code to find deprecated API use and other potential issues that could cause problems in Drupal 10.

Another tool you can use is the Drupal-check command-line tool. This tool uses the same underlying library as the Upgrade Status module to check custom code for deprecations and other potential pitfalls.

Refactoring Custom Code:

After identifying the troublesome parts of your custom code, the next step is to refactor them to be compatible with Drupal 10. Simply put, refactoring is the process of altering the code without changing its external behavior.

If the Upgrade Status module flagged some code as deprecated, the report will usually include suggestions for what to replace the deprecated code with. If it doesn't, the Drupal API documentation can be a helpful resource. You'll have to replace deprecated function calls, alter data structures, or even rearchitect some parts of your code to ensure compatibility.

In some cases, the changes required might be quite extensive, especially for code written for earlier versions of Drupal. If you're not comfortable doing this on your own, it may be worth hiring a Drupal developer with experience in migrations.

Finally, it's crucial to thoroughly test your changes to ensure that they work correctly and have not altered the expected behavior of your website. Automated testing tools can be a great help in this regard, ensuring your code is robust and ready for migration to Drupal 10.

Refactoring custom code for Drupal 10 can be an involved process, but it's a vital step in preparing your site for the migration. With careful planning and diligent testing, you can make your transition to Drupal 10 smoother and more successful.

 

The Challenge of Ensuring Consistent Performance

As with any major update or migration, moving to Drupal 10 can potentially impact the performance of your website. Performance, in this context, relates to how quickly your website loads, how smoothly it operates, and how well it manages the resources of the server it's hosted on.

While Drupal 10 is designed to be faster and more efficient than its predecessors, the migration process itself can lead to unexpected dips in performance. For instance, new modules or updated versions of existing ones may not be as optimised as those on your current site, slowing down load times. Similarly, potential compatibility issues with custom code may lead to increased server load, impacting website speed and overall performance.

Besides the technical aspects, user experience can also be affected during the migration process. Changes in layout due to a new theme or variations in navigational structures can disorient regular visitors, affecting user engagement and bounce rates.

These performance risks are a vital concern during migration because an optimally performing website is crucial for maintaining user engagement, SEO rankings, and overall user satisfaction.
 

 

The Solution: Monitoring Performance and Identifying Areas for Improvement

Monitoring your site’s performance pre, mid and post migration can play a pivotal role in ensuring a successful transition to Drupal 10. Here is how you can stay on top of it:

Benchmarking Performance Pre-Migration

Before you begin the migration process, document your website's current performance. This includes page load times, server response times, error rates, and any other relevant metrics. Use tools like Google PageSpeed Insights, GTMetrix, or Pingdom to gather this data. Having this information will allow you to compare performance before and after the migration, and identify any areas that need improvement.

Maintaining Performance During Migration

During the migration process, ensure that your website remains in an operational state. Regularly check for any potential performance drops or system errors. Drupal’s built-in watchdog logs and your server’s error logs are critical tools for this.

Optimising Performance Post-Migration

Once the migration is complete, return to your benchmark data and conduct the same tests again. If performance has dropped in any area, take steps to address this. Your solutions might include enabling caching, optimising images, reducing the number of HTTP requests, updating or replacing inefficient modules, or refactoring custom code for better performance.

Ensuring User Experience

Remember, performance isn't just about speed. User experience, which includes factors like site navigation and layout consistency, also plays a huge role. Use heat maps, session recording tools, and user feedback to understand how changes in Drupal 10 have affected the user experience and adjust accordingly.

Involving SEO

Ensure that your website's SEO hasn't been negatively impacted by the migration. Tools like Google Search Console can alert you to any crawl errors that might have occurred due to the migration. Also, ensure that any URLs that have changed due to the migration are properly redirected to prevent 404 errors.

By keeping a close eye on performance and being ready to take corrective action, you can ensure that your Drupal 10 migration is seamless and minimises disruption to your site's performance and user experience.

 

Conclusion

In this blog post, we have navigated through the challenges and solutions of migrating to Drupal 10, covering deprecated modules, custom code, and ensuring consistent performance.

Undeniably, the migration process can seem daunting, with the potential for bumps along the way. However, with meticulous planning, problem-solving, and performance monitoring, these hurdles can be overcome. The Upgrade Status module, refactoring custom code, and constant performance tracking are essential tools in your migration toolbox.

But, it's crucial to remember that while the migration to Drupal 10 requires effort, the rewards are absolutely worthwhile. With Drupal 10, you gain a faster, more secure, and highly efficient website that is designed to provide an enhanced user experience and keep you ahead in the digital space. It also ensures that your website is on the most recent and supported version of Drupal, protecting your online presence in the long run.

So, prepare yourself, embrace the upgrade, and take your website to new heights with Drupal 10. Remember, every challenge is an opportunity in disguise. Happy migrating!

Drupal Drupal 10 Drupal Planet Drupal migration