Hire a web Developer and Designer to upgrade and boost your online presence with cutting edge Technologies

Saturday, April 5, 2025

Building A Drupal To Storyblok Migration Tool: An Engineering Perspective

 shares the engineering and architectural choices made by the team at Storyblok and how real-world migration challenges were addressed using modern PHP practices.

Content management is evolving. The traditional monolithic CMS approach is giving way to headless architectures, where content management and presentation are decoupled. This shift brings new challenges, particularly when organizations need to migrate from legacy systems to modern headless platforms.

Our team encountered this scenario when creating a migration path from Drupal to Storyblok. These systems handle content architecture quite differently — Drupal uses an entity-field model integrated with PHP, while Storyblok employs a flexible Stories and Blocks structure designed for headless delivery.

If you just need to use a script to do a simple — yet extensible — content migration from Drupal to Storyblok, I already shared step-by-step instructions on how to download and use it. If you’re interested in the process of creating such a script so that you can write your own (possibly) better version, stay here!

We observed that developers sometimes struggle with manual content transfers and custom scripts when migrating between CMSs. This led us to develop and share our migration approach, which we implemented as an open-source tool that others could use as a reference for their migration needs.

Our solution combines two main components: a custom Drush command that handles content mapping and transformation and a new PHP client for Storyblok’s Management API that leverages modern language features for improved developer experience.

We’ll explore the engineering decisions behind this tool’s development, examining our architectural choices and how we addressed real-world migration challenges using modern PHP practices.

Note: You can find the complete source code of the migration tool in the Drupal exporter repo.

Planning The Migration Architecture

The journey from Drupal to Storyblok presents unique architectural challenges. The fundamental difference lies in how these systems conceptualize content: Drupal structures content as entities with fields, while Storyblok uses a component-based approach with Stories and Blocks.

Initial Requirements Analysis

A successful migration tool needs to understand both systems intimately. Drupal’s content model relies heavily on its Entity API, storing content as structured field collections within entities. A typical Drupal article might contain fields for the title, body content, images, and taxonomies. Storyblok, on the other hand, structures content as stories that contain blocks, reusable components that can be nested and arranged in a flexible way. It’s a subtle difference that shaped our technical requirements, particularly around content mapping and data transformation, but ultimately, it’s easy to see the relationships between the two content models.

Technical Constraints

Early in development, we identified several key constraints. Storyblok’s Management API enforces rate limits that affect how quickly we can transfer content. Media assets must first be uploaded and then linked. Error recovery becomes essential when migrating hundreds of pieces of content.

The brand-new Management API PHP client handles these constraints through built-in retry mechanisms and response validation, so in writing a migration script, we don’t need to worry about them.

Tool Selection

We chose Drush as our command-line interface for several reasons. First, it’s deeply integrated with Drupal’s bootstrap process, providing direct access to the Entity API and field data. Second, Drupal developers are already familiar with its conventions, making our tool more accessible.

The decision to develop a new Management API client came from our experience with the evolution of PHP since we developed the first PHP client, and our goal to provide developers with a dedicated tool for this specific API that offered an improved DX and a tailored set of features.

This groundwork shaped how we approached the migration workflow.

The Building Blocks: A New Management API Client

A content migration tool interacts heavily with Storyblok’s Management API &mdash, creating stories, uploading assets, and managing tags. Each operation needs to be reliable and predictable. Our brand-new client simplifies these interactions through intuitive method calls: The client handles authentication, request formatting, and response parsing behind the scenes, letting devs focus on content operations rather than API mechanics.

Design For Reliability

Content migrations often involve hundreds of API calls. Our client includes built-in mechanisms for handling common scenarios like rate limiting and failed requests. The response handling pattern provides clear feedback about operation success: A logger can be injected into the client class, as we did using the Drush logger in our migration script from Drupal.

Improving The Development Experience #

Beyond basic API operations, the client reduces cognitive load through predictable patterns. Data objects provide a structured way to prepare content for Storyblok: This pattern validates data early in the process, catching potential issues before they reach the API.

Designing The Migration Workflow

Moving from Drupal’s entity-based structure to Storyblok’s component model required careful planning of the migration workflow. Our goal was to create a process that would be both reliable and adaptable to different content structures.

Command Structure

The migration leverages Drupal’s entity query system to extract content systematically. By default, access checks were disabled (a reversible business decision) to focus solely on migrating published nodes.

Key Steps And Insights

  • Text Fields

    • Required minimal effort: values like value() mapped directly to Storyblok fields.
    • Rich text posed no encoding challenges, enabling straightforward 1:1 transfers.
  • Handling Images

    1. Upload: Assets were sent to an AWS S3 bucket.
    2. Link: Storyblok’s Asset API upload() method returned an object_id, simplifying field mapping.
    3. Assign: The asset ID and filename were attached to the story.
  • Managing Tags

    • Tags extracted from Drupal were pre-created via Storyblok’s Tag API (optional but ensures consistency).
    • When assigning tags to stories, Storyblok automatically creates missing ones, streamlining the process.

Why Staged Workflows Matter

The migration avoids broken references by prioritizing dependencies (assets first, tags next, content last). While pre-creating tags add control, teams can adapt this logic—for example, letting Storyblok auto-generate tags to save time.

Flexibility is key: every decision (access checks, tag workflows) can be adjusted to align with project goals.

Real-World Implementation Challenges

Migrating content between Drupal and Storyblok presents challenges that you, as the implementer, may encounter.

For example, when dealing with large datasets, you may find that Drupal sites with thousands of nodes can quickly hit the rate limits enforced by Storyblok’s management API. In such cases, a batching mechanism for your requests is worth considering. Instead of processing every node at once, you can process a subset of records, wait for a short period of time, and then continue.

Alternatively, you could use the createBulk method of the Story API in the Management API, which allows you to handle multiple story creations with built-in rate limit handling and retries. Another potential hurdle is the conversion of complex field types, especially when Drupal’s nested structures or Paragraph fields need to be mapped to Storyblok’s more flexible block-based model.

One approach is first to analyze the nesting depth and structure of the Drupal content, then flatten deeply nested elements into reusable Storyblok components while maintaining the correct hierarchy. For example, a paragraph field with embedded media and text can be split into blocks within Storyblok, with each component representing a logical section of content. By structuring data this way before migration, you ensure that content remains editable and properly structured in the new system.

Data consistency is another aspect that you need to manage carefully. When migrating hundreds of records, partial failures are always risky. One approach to managing this is to log detailed information for each migration operation and implement a retry mechanism for failed operations.

For example, wrapping API calls in a try-catch block and logging errors can be a practical way to ensure that no records are silently dropped. When dealing with fields such as taxonomy terms or tags created on the fly in Storyblok, you may run into duplication issues. A good practice is to perform a check before creating a new tag. This could involve maintaining a local cache of previously created tags and checking against them before sending a create request to the API.

The same goes for images; a check could ensure you don’t upload the same asset twice.

Lessons Learned And Looking Forward

A dedicated API client for Storyblok streamlined interactions, abstracting backend complexity while improving code maintainability. Early use of structured data objects to prepare content proved critical, enabling pre-emptive error detection and reducing API failures.

We also ran into some challenges and see room for improvement:

  • Encoding issues in rich text (e.g., HTML entities) were resolved with a pre-processing step
  • Performance bottlenecks with large text/images required memory optimization and refined request handling

Enhancements could include support for Drupal Layout Builder, advanced validation layers, or dynamic asset management systems.

Friday, April 4, 2025

AI:Web Components Vs. Framework Components: What’s The Difference?

 

Some critics question the agnostic nature of Web Components, with some even arguing that they are not real components. It explores this topic in-depth, comparing Web Components and framework components, highlighting their strengths and trade-offs, and evaluating their performance.

It might surprise you that a distinction exists regarding the word “component,” especially in front-end development, where “component” is often used and associated with front-end frameworks and libraries. A component is a code that encapsulates a specific functionality and presentation. Components in front-end applications have a similar function: building reusable user interfaces. However, their implementations are different.

Web — or “framework-agnostic” — components are standard web technologies for building reusable, self-sustained HTML elements. They consist of Custom Elements, Shadow DOM, and HTML template elements. On the other hand, framework components are reusable UIs explicitly tailored to the framework in which they are created. Unlike Web Components, which can be used in any framework, framework components are useless outside their frameworks.

Some critics question the agnostic nature of Web Components and even go so far as to state that they are not real components because they do not conform to the agreed-upon nature of components. This article comprehensively compares web and framework components, examines the arguments regarding Web Components agnosticism, and considers the performance aspects of Web and framework components.

What Makes A Component?

Several criteria could be satisfied for a piece of code to be called a component, but only a few are essential:

  • Reusability,
  • Props and data handling,
  • Encapsulation.

Reusability is the primary purpose of a component, as it emphasizes the DRY (don’t repeat yourself) principle. A component should be designed to be reused in different parts of an application or across multiple applications. Also, a component should be able to accept data (in the form of props) from its parent components and optionally pass data back through callbacks or events. Components are regarded as self-contained units; therefore, they should encapsulate their logic, styles, and state.

If there’s one thing we are certain of, framework components capture these criteria well, but what about their counterparts, Web Components?

Understanding Web Components

Web Components are a set of web APIs that allow developers to create custom, reusable HTML tags that serve a specific function. Based on existing web standards, they permit developers to extend HTML with new elements, custom behaviour, and encapsulated styling.

Web Components are built based on three web specifications:

  • Custom Elements,
  • Shadow DOM,
  • HTML templates.

Each specification can exist independently, but when combined, they produce a web component.

Custom Element #

The Custom Elements API makes provision for defining and using new types of DOM elements that can be reused.

// Define a Custom Element
class MyCustomElement extends HTMLElement {
  constructor() {
    super();
  }

  connectedCallback() {
    this.innerHTML = `
      <p>Hello from MyCustomElement!</p>
    `;
  }
}

// Register the Custom Element
customElements.define('my-custom-element', MyCustomElement);

Shadow DOM #

The Shadow DOM has been around since before the concept of web components. Browsers have used a nonstandard version for years for default browser controls that are not regular DOM nodes. It is a part of the DOM that is at least less reachable than typical light DOM elements as far as JavaScript and CSS go. These things are more encapsulated as standalone elements.

// Create a Custom Element with Shadow DOM
class MyShadowElement extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
  }

  connectedCallback() {
    this.shadowRoot.innerHTML = `
      <style>
        p {
          color: green;
        }
      </style>
      <p>Content in Shadow DOM</p>
    `;
  }
}

// Register the Custom Element
customElements.define('my-shadow-element', MyShadowElement);

HTML Templates #

HTML Templates API enables developers to write markup templates that are not loaded at the start of the app but can be called at runtime with JavaScript. HTML templates define the structure of Custom Elements in Web Components.

// my-component.js
export class MyComponent extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
  }

  connectedCallback() {
    this.shadowRoot.innerHTML = `
      <style>
        p {
          color: red;
        }
      </style>
      <p>Hello from ES Module!</p>
    `;
  }
}

// Register the Custom Element
customElements.define('my-component', MyComponent);

<!-- Import the ES Module -->
<script type="module">
  import { MyComponent } from './my-component.js';
</script>

Web Components are often described as framework-agnostic because they rely on native browser APIs rather than being tied to any specific JavaScript framework or library. This means that Web Components can be used in any web application, regardless of whether it is built with React, Angular, Vue, or even vanilla JavaScript. Due to their supposed framework-agnostic nature, they can be created and integrated into any modern front-end framework and still function with little to no modifications. But are they actually framework-agnostic?

The Reality Of Framework-Agnosticism In Web Components #

Framework-agnosticism is a term describing self-sufficient software — an element in this case — that can be integrated into any framework with minimal or no modifications and still operate efficiently, as expected.

Web Components can be integrated into any framework, but not without changes that can range from minimal to complex, especially the styles and HTML arrangement. Another change Web Components might experience during integration includes additional configuration or polyfills for full browser support. This drawback is why some developers do not consider Web Components to be framework-agnostic. Notwithstanding, besides these configurations and edits, Web Components can easily fit into any front-end framework, including but not limited to React, Angular, and Vue.

Framework Components: Strengths And Limitations

Framework components are framework-specific reusable bits of code. They are regarded as the building blocks of the framework on which they are built and possess several benefits over Web Components, including the following:

  • An established ecosystem and community support,
  • Developer-friendly integrations and tools,
  • Comprehensive documentation and resources,
  • Core functionality,
  • Tested code,
  • Fast development,
  • Cross-browser support, and
  • Performance optimizations.

Examples of commonly employed front-end framework elements include React components, Vue components, and Angular directives. React supports a virtual DOM and one-way data binding, which allows for efficient updates and a component-based model. Vue is a lightweight framework with a flexible and easy-to-learn component system. Angular, unlike React, offers a two-way data binding component model with a TypeScript focus. Other front-end framework components include Svelte components, SolidJS components, and more.

Framework layer components are designed to operate under a specific JavaScript framework such as React, Vue, or Angular and, therefore, reside almost on top of the framework architecture, APIs, and conventions. For instance, React components use JSX and state management by React, while Angular components leverage Angular template syntax and dependency injection. As far as benefits, it has excellent developer experience performance, but as far as drawbacks are concerned, they are not flexible or reusable outside the framework.

In addition, a state known as vendor lock-in is created when developers become so reliant on some framework or library that they are unable to switch to another. This is possible with framework components because they are developed to be operational only in the framework environment.

Comparative Analysis

Framework and Web Components have their respective strengths and weaknesses and are appropriate to different scenarios. However, a comparative analysis based on several criteria can help deduce the distinction between both.

Encapsulation And Styling: Scoped Vs. Isolated #

Encapsulation is a trademark of components, but Web Components and framework components handle it differently. Web Components provide isolated encapsulation with the Shadow DOM, which creates a separate DOM tree that shields a component’s styles and structure from external manipulation. That ensures a Web Component will look and behave the same wherever it is used.

However, this isolation can make it difficult for developers who need to customize styles, as external CSS cannot cross the Shadow DOM without explicit workarounds (e.g., CSS custom properties). Scoped styling is used by most frameworks, which limit CSS to a component using class names, CSS-in-JS, or module systems. While this dissuades styles from leaking outwards, it does not entirely prevent external styles from leaking in, with the possibility of conflicts. Libraries like Vue and Svelte support scoped CSS by default, while React often falls back to libraries like styled-components.

Reusability And Interoperability

Web Components are better for reusable components that are useful for multiple frameworks or vanilla JavaScript applications. In addition, they are useful when the encapsulation and isolation of styles and behavior must be strict or when you want to leverage native browser APIs without too much reliance on other libraries.

Framework components are, however, helpful when you need to leverage some of the features and optimisations provided by the framework (e.g., React reconciliation algorithm, Angular change detection) or take advantage of the mature ecosystem and tools available. You can also use framework components if your team is already familiar with the framework and conventions since it will make your development process easier.

Performance Considerations #

Another critical factor in determining web vs. framework components is performance. While both can be extremely performant, there are instances where one will be quicker than the other.

For Web Components, implementation in the native browser can lead to optimised rendering and reduced overhead, but older browsers may require polyfills, which add to the initial load. While React and Angular provide specific optimisations (e.g., virtual DOM, change detection) that will make performance improvements on high-flow, dynamic applications, they add overhead due to the framework runtime and additional libraries.

Developer Experience

Developer experience is another fundamental consideration regarding Web Components versus framework components. Ease of use and learning curve can play a large role in determining development time and manageability. Availability of tooling and community support can influence developer experience, too.

Web Components use native browser APIs and, therefore, are comfortable to developers who know HTML, CSS, and JavaScript but have a steeper learning curve due to additional concepts like the Shadow DOM, custom elements, and templates that have a learning curve attached to them. Also, Web Components have a smaller community and less community documentation compared to famous frameworks like React, Angular, and Vue.

Side-by-Side Comparison #

Web Components BenefitsFramework Components Benefits
Native browser support can lead to efficient rendering and reduced overhead.Frameworks like React and Angular provide specific optimizations (e.g., virtual DOM, change detection) that can improve performance for large, dynamic applications.
Smaller bundle sizes and native browser support can lead to faster load times.Frameworks often provide tools for optimizing bundle sizes and lazy loading components.
Leverage native browser APIs, making them accessible to developers familiar with HTML, CSS, and JavaScript.Extensive documentation, which makes it easier for developers to get started.
Native browser support means fewer dependencies and the potential for better performance.Rich ecosystem with extensive tooling, libraries, and community support.
Web Components DrawbacksFramework Components Drawbacks
Older browsers may require polyfills, which can add to the initial load time.Framework-specific components can add overhead due to the framework’s runtime and additional libraries.
Steeper learning curve due to additional concepts like Shadow DOM and Custom Elements.Requires familiarity with the framework’s conventions and APIs.
Smaller ecosystem and fewer community resources compared to popular frameworks.Tied to the framework, making it harder to switch to a different framework.

To summarize, the choice between Web Components and framework components depends on the specific need of your project or team, which can include cross-framework reusability, performance, and developer experience.

Conclusion

Web Components are the new standard for agnostic, interoperable, and reusable components. Although they need further upgrades and modifications in terms of their base technologies to meet framework components standards, they are entitled to the title “components.” Through a detailed comparative analysis, we’ve explored the strengths and weaknesses of Web Components and framework components, gaining insight into their differences. Along the way, we also uncovered useful workarounds for integrating web components into front-end frameworks for those interested in that approach.

References