⭐ If you would like to buy me a coffee, well thank you very much that is mega kind! : https://www.buymeacoffee.com/honeyvig Hire a web Developer and Designer to upgrade and boost your online presence with cutting edge Technologies
Showing posts with label Headless. Show all posts
Showing posts with label Headless. Show all posts

Wednesday, February 19, 2025

Integrations: From Simple Data Transfer To Modern Composable Architectures

 In today’s web development landscape, the concept of a monolithic application has become increasingly rare. Modern applications are composed of multiple specialized services, each of which handles specific aspects of functionality. This shift didn’t happen overnight — it’s the result of decades of evolution in how we think about and implement data transfer between systems. Let’s explore this journey and see how it shapes modern architectures, particularly in the context of headless CMS solutions.

When computers first started talking to each other, the methods were remarkably simple. In the early days of the Internet, systems exchanged files via FTP or communicated via raw TCP/IP sockets. This direct approach worked well for simple use cases but quickly showed its limitations as applications grew more complex.

# Basic socket server example
import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 12345))
server_socket.listen(1)

while True:
    connection, address = server_socket.accept()
    data = connection.recv(1024)
    # Process data
    connection.send(response)

The real breakthrough in enabling complex communication between computers on a network came with the introduction of Remote Procedure Calls (RPC) in the 1980s. RPC allowed developers to call procedures on remote systems as if they were local functions, abstracting away the complexity of network communication. This pattern laid the foundation for many of the modern integration approaches we use today.

At its core, RPC implements a client-server model where the client prepares and serializes a procedure call with parameters, sends the message to a remote server, the server deserializes and executes the procedure, and then sends the response back to the client.

Here’s a simplified example using Python’s XML-RPC.

# Server
from xmlrpc.server import SimpleXMLRPCServer

def calculate_total(items):
    return sum(items)

server = SimpleXMLRPCServer(("localhost", 8000))
server.register_function(calculate_total)
server.serve_forever()

# Client
import xmlrpc.client

proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
try:
    result = proxy.calculate_total([1, 2, 3, 4, 5])
except ConnectionError:
    print("Network error occurred")

RPC can operate in both synchronous (blocking) and asynchronous modes.

Modern implementations such as gRPC support streaming and bi-directional communication. In the example below, we define a gRPC service called Calculator with two RPC methods, Calculate, which takes a Numbers message and returns a Result message, and CalculateStream, which sends a stream of Result messages in response.

// protobuf
service Calculator {
  rpc Calculate(Numbers) returns (Result);
  rpc CalculateStream(Numbers) returns (stream Result);
}

Modern Integrations: The Rise Of Web Services And SOA

The late 1990s and early 2000s saw the emergence of Web Services and Service-Oriented Architecture (SOA). SOAP (Simple Object Access Protocol) became the standard for enterprise integration, introducing a more structured approach to system communication.

<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <soap:Header>
  </soap:Header>
  <soap:Body>
    <m:GetStockPrice xmlns:m="http://www.example.org/stock">
      <m:StockName>IBM</m:StockName>
    </m:GetStockPrice>
  </soap:Body>
</soap:Envelope>

While SOAP provided robust enterprise features, its complexity, and verbosity led to the development of simpler alternatives, especially the REST APIs that dominate Web services communication today.

But REST is not alone. Let’s have a look at some modern integration patterns.

RESTful APIs

REST (Representational State Transfer) has become the de facto standard for Web APIs, providing a simple, stateless approach to manipulating resources. Its simplicity and HTTP-based nature make it ideal for web applications.

First defined by Roy Fielding in 2000 as an architectural style on top of the Web’s standard protocols, its constraints align perfectly with the goals of the modern Web, such as performance, scalability, reliability, and visibility: client and server separated by an interface and loosely coupled, stateless communication, cacheable responses.

In modern applications, the most common implementations of the REST protocol are based on the JSON format, which is used to encode messages for requests and responses.

// Request
async function fetchUserData() {
  const response = await fetch('https://api.example.com/users/123');
  const userData = await response.json();
  return userData;
}

// Response
{
  "id": "123",
  "name": "John Doe",
  "_links": {
    "self": { "href": "/users/123" },
    "orders": { "href": "/users/123/orders" },
    "preferences": { "href": "/users/123/preferences" }
  }
}

GraphQL

GraphQL emerged from Facebook’s internal development needs in 2012 before being open-sourced in 2015. Born out of the challenges of building complex mobile applications, it addressed limitations in traditional REST APIs, particularly the issues of over-fetching and under-fetching data.

At its core, GraphQL is a query language and runtime that provides a type system and declarative data fetching, allowing the client to specify exactly what it wants to fetch from the server.

// graphql
type User {
  id: ID!
  name: String!
  email: String!
  posts: [Post!]!
}

type Post {
  id: ID!
  title: String!
  content: String!
  author: User!
  publishDate: String!
}

query GetUserWithPosts {
  user(id: "123") {
    name
    posts(last: 3) {
      title
      publishDate
    }
  }
}

Often used to build complex UIs with nested data structures, mobile applications, or microservices architectures, it has proven effective at handling complex data requirements at scale and offers a growing ecosystem of tools.

Webhooks

Modern applications often require real-time updates. For example, e-commerce apps need to update inventory levels when a purchase is made, or content management apps need to refresh cached content when a document is edited. Traditional request-response models can struggle to meet these demands because they rely on clients’ polling servers for updates, which is inefficient and resource-intensive.

Webhooks and event-driven architectures address these needs more effectively. Webhooks let servers send real-time notifications to clients or other systems when specific events happen. This reduces the need for continuous polling. Event-driven architectures go further by decoupling application components. Services can publish and subscribe to events asynchronously, and this makes the system more scalable, responsive, and simpler.

import fastify from 'fastify';

const server = fastify();
server.post('/webhook', async (request, reply) => {
  const event = request.body;
  
  if (event.type === 'content.published') {
    await refreshCache();
  }
  
  return reply.code(200).send();
});

This is a simple Node.js function that uses Fastify to set up a web server. It responds to the endpoint /webhook, checks the type field of the JSON request, and refreshes a cache if the event is of type content.published.

With all this background information and technical knowledge, it’s easier to picture the current state of web application development, where a single, monolithic app is no longer the answer to business needs, but a new paradigm has emerged: Composable Architecture.

Composable Architecture And Headless CMSs

This evolution has led us to the concept of composable architecture, where applications are built by combining specialized services. This is where headless CMS solutions have a clear advantage, serving as the perfect example of how modern integration patterns come together.

Headless CMS platforms separate content management from content presentation, allowing you to build specialized frontends relying on a fully-featured content backend. This decoupling facilitates content reuse, independent scaling, and the flexibility to use a dedicated technology or service for each part of the system.

Take Storyblok as an example. Storyblok is a headless CMS designed to help developers build flexible, scalable, and composable applications. Content is exposed via API, REST, or GraphQL; it offers a long list of events that can trigger a webhook. Editors are happy with a great Visual Editor, where they can see changes in real time, and many integrations are available out-of-the-box via a marketplace.

Imagine this ContentDeliveryService in your app, where you can interact with Storyblok’s REST API using the open source JS Client:

import StoryblokClient from "storyblok-js-client";

class ContentDeliveryService {
  constructor(private storyblok: StoryblokClient) {}

  async getPageContent(slug: string) {
    const { data } = await this.storyblok.get(`cdn/stories/${slug}`, {
      version: 'published',
      resolve_relations: 'featured-products.products'
    });

    return data.story;
  }

  async getRelatedContent(tags: string[]) {
    const { data } = await this.storyblok.get('cdn/stories', {
      version: 'published',
      with_tag: tags.join(',')
    });

    return data.stories;
  }
}

The last piece of the puzzle is a real example of integration.

Again, many are already available in the Storyblok marketplace, and you can easily control them from the dashboard. However, to fully leverage the Composable Architecture, we can use the most powerful tool in the developer’s hand: code.

Let’s imagine a modern e-commerce platform that uses Storyblok as its content hub, Shopify for inventory and orders, Algolia for product search, and Stripe for payments.

Once each account is set up and we have our access tokens, we could quickly build a front-end page for our store. This isn’t production-ready code, but just to get a quick idea, let’s use React to build the page for a single product that integrates our services.

First, we should initialize our clients:

import StoryblokClient from "storyblok-js-client";
import { algoliasearch } from "algoliasearch";
import Client from "shopify-buy";


const storyblok = new StoryblokClient({
  accessToken: "your_storyblok_token",
});
const algoliaClient = algoliasearch(
  "your_algolia_app_id",
  "your_algolia_api_key",
);
const shopifyClient = Client.buildClient({
  domain: "your-shopify-store.myshopify.com",
  storefrontAccessToken: "your_storefront_access_token",
});

Given that we created a blok in Storyblok that holds product information such as the product_id, we could write a component that takes the productSlug, fetches the product content from Storyblok, the inventory data from Shopify, and some related products from the Algolia index:

async function fetchProduct() {
  // get product from Storyblok
  const { data } = await storyblok.get(`cdn/stories/${productSlug}`);

  // fetch inventory from Shopify
  const shopifyInventory = await shopifyClient.product.fetch(
    data.story.content.product_id
  );

  // fetch related products using Algolia
  const { hits } = await algoliaIndex.search("products", {
    filters: `category:${data.story.content.category}`,
  });
}

We could then set a simple component state:

const [productData, setProductData] = useState(null);
const [inventory, setInventory] = useState(null);
const [relatedProducts, setRelatedProducts] = useState([]);

useEffect(() =>
  // ...
  // combine fetchProduct() with setState to update the state
  // ...

  fetchProduct();
}, [productSlug]);

And return a template with all our data:

<h1>{productData.content.title}</h1>
<p>{productData.content.description}</p>
<h2>Price: ${inventory.variants[0].price}</h2>
<h3>Related Products</h3>
<ul>
  {relatedProducts.map((product) => (
    <li key={product.objectID}>{product.name}</li>
  ))}
</ul>

We could then use an event-driven approach and create a server that listens to our shop events and processes the checkout with Stripe (credits to Manuel Spigolon for this tutorial):

const stripe = require('stripe')

module.exports = async function plugin (app, opts) {
  const stripeClient = stripe(app.config.STRIPE_PRIVATE_KEY)

  server.post('/create-checkout-session', async (request, reply) => {
    const session = await stripeClient.checkout.sessions.create({
      line_items: [...], // from request.body
      mode: 'payment',
      success_url: "https://your-site.com/success",
      cancel_url: "https://your-site.com/cancel",
    })

    return reply.redirect(303, session.url)
  })
// ...

And with this approach, each service is independent of the others, which helps us achieve our business goals (performance, scalability, flexibility) with a good developer experience and a smaller and simpler application that’s easier to maintain.

Conclusion

The integration between headless CMSs and modern web services represents the current and future state of high-performance web applications. By using specialized, decoupled services, developers can focus on business logic and user experience. A composable ecosystem is not only modular but also resilient to the evolving needs of the modern enterprise.

These integrations highlight the importance of mastering API-driven architectures and understanding how different tools can harmoniously fit into a larger tech stack.

In today’s digital landscape, success lies in choosing tools that offer flexibility and efficiency, adapt to evolving demands, and create applications that are future-proof against the challenges of tomorrow.

If you want to dive deeper into the integrations you can build with Storyblok and other services, check out Storyblok’s integrations page. You can also take your projects further by creating your own plugins with Storyblok’s plugin development resources.

Thursday, April 25, 2024

How To Work With GraphQL In WordPress In 2024

 What options do we have for integrating GraphQL with WordPress in 2024? Leonardo Losoviz describes what developments have taken place in this space during the last three years.

Three years ago, I published “Making GraphQL Work In WordPress,” where I compared the two leading GraphQL servers available for WordPress at the time: WPGraphQL and Gato GraphQL. In the article, I aimed to delineate the scenarios best suited for each.

Full disclosure: I created Gato GraphQL, originally known as GraphQL API for WordPress, as referenced in the article.

A lot of new developments have happened in this space since my article was published, and it’s a good time to consider what’s changed and how it impacts the way we work with GraphQL data in WordPress today.

This time, though, let’s focus less on when to choose one of the two available servers and more on the developments that have taken place and how both plugins and headless WordPress, in general, have been affected.

Headless Is The Future Of WordPress (And Shall Always Be)

There is no going around it: Headless is the future of WordPress! At least, that is what we have been reading in posts and tutorials for the last eight or so years. Being Argentinian, this reminds me of an old joke that goes, “Brazil is the country of the future and shall always be!” The future is both imminent and far away.

Truth is, WordPress sites that actually make use of headless capabilities — via GraphQL or the WP REST API — represent no more than a small sliver of the overall WordPress market. WPEngine may have the most extensive research into headless usage in its “The State of Headless” report. Still, it’s already a few years old and focused more on both the general headless movement (not just WordPress) and the context of enterprise organizations. But the future of WordPress, according to the report, is written in the clouds:

“Headless is emphatically here, and with the rapid rise in enterprise adoption from 2019 (53%) to 2021 (64%), it’s likely to become the industry standard for large-scale organizations focused on building and maintaining a powerful, connected digital footprint. […] Because it’s already the most popular CMS in the world, used by many of the world’s largest sites, and because it’s highly compatible as a headless CMS, bringing flexibility, extensibility, and tons of features that content creators love, WordPress is a natural fit for headless configurations.”

Just a year ago, a Reddit user informally polled people in r/WordPress, and while it’s far from scientific, the results are about as reliable as the conjecture before it:

106 are using it, 410 are not, and 361 do not know how to do it.
Informal Reddit poll results. (Large preview)

Headless may very well be the future of WordPress, but the proof has yet to make its way into everyday developer stacks. It could very well be that general interest and curiosity are driving the future more than tangible works, as another of WPEngine’s articles from the same year as the bespoke report suggests when identifying “Headless WordPress” as a hot search term. This could just as well be a lot more smoke than fire.

That’s why I believe that “headless” is not yet a true alternative to a traditional WordPress stack that relies on the WordPress front-end architecture. I see it more as another approach, or flavor, to building websites in general and a niche one at that.

That was all true merely three years ago and is still true today.

WPEngine “Owns” Headless WordPress

It’s no coincidence that we’re referencing WPEngine when discussing headless WordPress because the hosting company is heavily betting on it becoming the de facto approach to WordPress development.

Take, for instance, WPEngine’s launch of Faust.js, a headless framework with WPGraphQL as its foundation. Faust.js is an opinionated framework that allows developers to use WordPress as the back-end content management system and Next.js to render the front-end side of things. Among other features, Faust.js replicates the WordPress template system for Next.js, making the configuration to render posts and pages from WordPress data a lot easier out of the box.

WPEngine is well-suited for this task, as it can offer hosting for both Node.js and WordPress as a single solution via its Atlas platform. WPEngine also bought the popular Advanced Custom Fields (ACF) plugin that helps define relationships among entities in the WordPress data model. Add to that the fact that WPEngine has taken over the Headless WordPress Discord server, with discussions centered around WPGraphQL, Faust, Atlas, and ACF. It could very well be named the WPEngine-Powered Headless WordPress server instead.

But WPEngine’s agenda and dominance in the space is not the point; it’s more that they have a lot of skin in the game as far as anticipating a headless WordPress future. Even more so now than three years ago.

GraphQL API for WordPress → Gato GraphQL

I created a plugin several years ago called GraphQL API for WordPress to help support headless WordPress development. It converts data pulled from the WordPress REST API into structured GraphQL data for more efficient and flexible queries based on the content managed and stored in WordPress.

More recently, I released a significantly updated version of the plugin, so updated that I chose to rename it to Gato GraphQL, and it is now freely available in the WordPress Plugin Directory. It’s a freemium offering like many WordPress plugin pricing models. The free, open-source version in the plugin directory provides the GraphQL server, maps the WordPress data model into the GraphQL schema, and provides several useful features, including custom endpoints and persisted queries. The paid commercial add-on extends the plugin by supporting multiple query executions, automation, and an HTTP client to interact with external services, among other advanced features.

I know this sounds a lot like a product pitch but stick with me because there’s a point to the decision I made to revamp my existing GraphQL plugin and introduce a slew of premium services as features. It fits with my belief that

WordPress is becoming more and more open to giving WordPress developers and site owners a lot more room for innovation to work collaboratively and manage content in new and exciting ways both in and out of WordPress.

JavaScript Frameworks & Headless WordPress

Gatsby was perhaps the most popular and leading JavaScript framework for creating headless WordPress sites at the time my first article was published in 2021. These days, though, Gatsby is in steep decline and its integration with WordPress is no longer maintained.

Next.js was also a leader back then and is still very popular today. The framework includes several starter templates designed specifically for headless WordPress instances.

SvelteKit and Nuxt are surging these days and are considered good choices for establishing headless WordPress, as was discussed during WordCamp Asia 2024.

Today, in 2024, we continue to see new JavaScript framework entrants in the space, notably Astro. Despite Gatsby’s recent troubles, the landscape of using JavaScript frameworks to create front-end experiences from the WordPress back-end is largely the same as it was a few years ago, if maybe a little easier, thanks to the availability of new templates that are integrated right out of the box.

GraphQL Transcends Headless WordPress

The biggest difference between the WPGraphQL and Gato GraphQL plugins is that, where WPGraphQL is designed to convert REST API data into GraphQL data in a single direction, Gato GraphQL uses GraphQL data in both directions in a way that can be used to manage non-headless WordPress sites as well. I say this not as a way to get you to use my plugin but to help describe how GraphQL has evolved to the point where it is useful for more cases than headless WordPress sites.

Managing a WordPress site via GraphQL is possible because GraphQL is an agnostic tool for interacting with data, whatever that interaction may be. GraphQL can fetch data from the server, modify it, store it back on the server, and invoke external services. These interactions can all be coded within a single query.

GraphQL can then be used to regex search and replace a string in all posts, which is practical when doing site migrations. We can also import a post from another WordPress site or even from an RSS feed or CSV source.

And thanks to the likes of WordPress hooks and WP-Cron, executing a GraphQL query can be an automated task. For instance, whenever the publish_post hook is triggered — i.e., a new post on the site is published — we can execute certain actions, like an email notification to the site admin, or generate a featured image with AI if the post lacks one.

In short, GraphQL works both ways and opens up new possibilities for better developer and author experiences!

GraphQL Becomes A “Core” Feature In WordPress 6.5

I have gone on record saying that GraphQL should not be a core part of WordPress. There’s a lot of reasoning behind my opinion, but what it boils down to is that the WP REST API is perfectly capable of satisfying our needs for passing data around, and adding GraphQL to the mix could be a security risk in some conditions.

My concerns aside, GraphQL officially became a first-class citizen of WordPress when it was baked into WordPress 6.5 with the introduction of Plugin Dependencies, a feature that allows plugins to identify other plugins as dependencies. We see this in the form of a new “Requires Plugins” comment in a plugin’s header:

/**
 * Plugin Name: My Ecommerce Payments for Gato GraphQL
 * Requires Plugins: gatographql
 */

WordPress sees which plugins are needed for the current plugin to function properly and installs everything together at the same time, assuming that the dependencies are readily available in the WordPress Plugin Directory.

So, check this out. Since WPGraphQL and Gato GraphQL are in the plugin directory, we can now create another plugin that internally uses GraphQL and distributes it via the plugin directory or, in general, without having to indicate how to install it. For instance, we can now use GraphQL to fetch data to render the plugin’s blocks.

In other words, plugins are now capable of more symbiotic relationships that open even more possibilities! Beyond that, every plugin in the WordPress Plugin Directory is now technically part of WordPress Core, including WPGraphQL and Gato GraphQL. So, yes, GraphQL is now technically a “core” feature that can be leveraged by other developers.

Helping WordPress Lead The CMS Market, Again

While delivering the keynote presentation during WordCamp Asia 2024, Human Made co-founder Noel Tock discussed the future of WordPress. He argues that WordPress growth has stagnated in recent years, thanks to a plethora of modern web services capable of interacting and resulting in composable content management systems tailored to certain developers in a way that WordPress simply isn’t.

Historical line chart showing monolithic WordPress declining and composable CMSs growing in innovation over time.
Slide taken from Noel Tock's WordCamp Asia 2024 keynote address. (Large preview)

Tock continues to explain how WordPress can once again become a growth engine by cleaning up the WordPress plugin ecosystem and providing first-class integrations with external services.

Historical line chart showing monolithic WordPress declining and composable CMSs growing in innovation over time.
Slide taken from Noel Tock's WordCamp Asia 2024 keynote address. (Large preview)

Do you see where I am going with this? GraphQL could play an instrumental role in WordPress’s future success. It very well could be the link between WordPress and all the different services it interacts with, positioning WordPress at the center of the web. The recent Plugin Dependencies feature we noted earlier is a peek at what WordPress could look like as it adopts more composable approaches to content management that support its position as a market leader.

Conclusion

“Headless” WordPress is still “the future” of WordPress. But as we’ve discussed, there’s very little actual movement towards that future as far as developers buying into it despite displaying deep interest in headless architectures, with WordPress purely playing the back-end role.

There are new and solid frameworks that rely on GraphQL for querying data, and those won’t go away anytime soon. And those frameworks are the ones that rely on existing WordPress plugins that consume data from the WordPress REST API and convert it to structured GraphQL data.

Meanwhile, WordPress is making strides toward greater innovation as plugin developers are now able to leverage other plugins as dependencies for their plugins. Every plugin listed in the WordPress Plugin Directory is essentially a feature of WordPress Core, including WPGraphQL and Gato GraphQL. That means GraphQL is readily available for any plugin developer to tap into as of WordPress 6.5.

GraphQL can be used not only for headless but also to manage the WordPress site. Whenever data must be transformed, whether locally or by invoking an external service, GraphQL can be the tool to do it. That even means that data transforms can be triggered automatically to open up new and interesting ways to manage content, both inside and outside of WordPress. It works both ways!

So, yes, even though headless is the future of WordPress (and shall always be), GraphQL could indeed be a key component in making WordPress once again an innovative force that shapes the future of CMS.

Thursday, January 18, 2024

An Introduction To Full Stack Composability

 A well-designed composable system should not only consider the technical aspects but also take into account the nature of the content it handles. To help us with that, we can use a Headless Content Management system such as Storyblok.

Composability is not only about building a design system. We should create and manage reusable components in the frontend and the UX of our website, as well as coordinate with the backend and the content itself.

In this article, we’ll discuss how to go through both the server and the client sides of our projects and how to align with the content that we’ll manage. We’ll also compare how to implement composable logic into our code using different approaches provided by React-based frameworks like Remix and Next.js.

Composable Architecture #

In the dynamic landscape of web development, the concept of composability has emerged as a key player in crafting scalable, maintainable, and efficient systems. It goes beyond merely constructing design systems; it encompasses the creation and management of reusable components across the entire spectrum of web development, from frontend UX to backend coordination and content management.

Composability is the art of building systems in a modular and flexible way. It emphasizes creating components that are not only reusable but can seamlessly fit together, forming a cohesive and adaptable architecture. This approach not only enhances the development process but also promotes consistency and scalability across projects.

Composable Architecture
Composable Architecture (Large preview)

We define “composable architecture” as the idea of building software systems from small, independent components that you can combine to form a complete system. Think of a system as a set of LEGO pieces. Putting them together, you can build cool structures, figures, and other creations. But the cool thing about those blocks is that you can exchange them, reuse them for other creations, and add new pieces to your existing models.

Parts Of A Composable Architecture #

To manage a composable architecture for our projects, we have to connect two parts:

Modular Components #

Break down the system into independent, self-contained modules or components. Modular components can be developed, tested, and updated independently, promoting reusability and easier maintenance.

When we talk about modular components, we are referring to units like:

  • Microservices
    The architectural style for developing software applications as a set of small, independent services that communicate with each other through well-defined APIs. The application is broken down into a collection of loosely coupled and independently deployable services, each responsible for a specific business capability.
  • Headless Applications
    In a headless architecture, the application’s logic and functionality are decoupled from the presentation layer, allowing it to function independently of a specific user interface.
  • Packaged Business Capabilities (PBC)
    A set of activities, products, and services bundled together and offered as a complete solution. It is a very common concept in the e-commerce environment.

APIs #

As the components of our architecture can manage different types of data, processes, and tasks of different natures, they need a common language to communicate between them. Components should expose consistent and well-documented APIs (Application Programming Interfaces). An API is a set of rules and protocols that allows one software application to interact with another. APIs define the methods and data formats that applications can use to communicate with each other.

Benefits Of A Composable Architecture #

When applying a composable approach to the architecture of our projects, we will see some benefits and advantages:

  • Easy to reuse.
    Components are designed to be modular and independent. This makes it easy to reuse them in different parts of the system or entirely different systems. Reusability can significantly reduce development time and effort, as well as improve consistency across different projects.
  • Easy to scale.
    When the demand for a particular service or functionality increases, you can scale the system by adding more instances of the relevant components without affecting the entire architecture. This scalability is essential for handling growing workloads and adapting to changing business requirements.
  • Easy to maintain.
    Each component is self-contained. If there’s a need to update or fix a specific feature, it can be done without affecting the entire system. This modularity makes it easier to identify, isolate, and address issues, reducing the impact of maintenance activities on the overall system.
  • Independence from vendors.
    This reduces the dependence on specific vendors for components, making it easier to switch or upgrade individual parts without disrupting the entire system.
  • Faster development and iteration.
    Development teams can work on different components concurrently. This parallel development accelerates the overall development process. Additionally, updates and improvements can be rolled out independently.

The MACH Architecture #

An example of composability is what is called the MACH architecture. The MACH acronym breaks down into Microservices, API-first, Cloud-native, and Headless. This approach is focused on applying composability in a way that allows you to mold the entire ecosystem of your projects and organization to make it align with business needs.

One of the main ideas of the MACH approach is to let marketers, designers, and front-end developers do their thing without having to worry about the backend in the process. They can tweak the look and feel on the fly, run tests, and adapt to what customers want without slowing down the whole operation.

With MACH architecture, getting to an MVP (minimum viable product) is like a rocket ride. Developers can whip up quick prototypes, and businesses can test out their big ideas before going all-in.

An example of MACH approach: A Headless CMS (Large preview)” alt=” An example of MACH approach: A Headless CMS

MACH also helps to resolve poor web performance, using improved services and tools that apply specifically to each one of the different components of your organization’s ecosystem. For example, in the e-commerce game, time is money — those old-school sites using monolithic platforms lose sales to the speedy and flexible ones built with a composable approach. MACH lets you create a custom IT setup using the hottest tech out there.

Composability With React #

We can dive deeper and transfer the same composability concept to the implementation of the user interface and experience of our application. React encourages developers to break down user interfaces into small, reusable components that can be composed together to create complex UIs. Each React component is designed to encapsulate a specific piece of functionality or user interface element, promoting a modular and composable architecture. This approach facilitates code reuse, as components can be easily shared and integrated into various parts of an application.

React’s component-based architecture simplifies the development process by allowing developers to focus on building small, self-contained units of functionality. These components can then be combined to create more sophisticated features and build new “higher-level” components. The reusability of React components is a key benefit, as it promotes a more efficient and maintainable codebase. With this idea in mind, we can build design systems for our projects, as well as following approaches like the Atomic Design principle.

Going Full Stack #

But we can go even further and apply the composable approach to our backend and server-side logic, too. React-based frameworks, such as Remix and Next.js, provide powerful tools for implementing composability in web applications while getting the best from different rendering approaches, such as server-side rendering and static generation. Let’s see a couple of concepts applied in both Next.js and Remix that can help us implement server logic while keeping the composability of our code.

Full Stack Composability with Next.js: React Server Components #

React Server Components were introduced by the React team to address challenges related to server-rendered content and enhance the composability of React applications. Composability, in the context of React Server Components, refers to the ability to break down a user interface into smaller, reusable units that can be efficiently managed on the server side. React Server Components take the idea of composability a step further by allowing certain components to be rendered and processed on the server rather than the client. This is particularly useful for large-scale applications where rendering everything on the client side might lead to performance bottlenecks.

Next.js, a React-based framework, includes React Server Components as the default approach when creating and managing components on a project, since its version 13. Some of the benefits identified when using React Server Components are:

  • Move data fetching operations to the server, closer to the data source. This also reduces the amount of requests the client needs to make while using the power of processing the web servers offer, compared to the processing capacity of the client devices.
  • Better security when managing and rendering content.
  • Better caching strategies.
  • Improved Initial Page Load and First Contentful Paint (FCP).
  • Reduce bundle sizes.

Full Stack Composability With Remix: Full Stack Components #

One of Remix’s key principles is the ability to create composable route components, allowing developers to build complex user interfaces by combining smaller, self-contained pieces.

Kent C. Dodds, a very valuable member of the dev community, introduced the concept of Full Stack Components to describe the way the Remix framework allows the developers to create components, encapsulating the data fetching and processing they require and involve, in a single file or module that manages both client-side and server-side logic.

With the help of Loader and Action functions, in addition to the Resource Routes, Remix allows developers to add server-side logic, like fetching or data mutations, on the same file where we define the visual representation of the component.

Aligning With The Content #

Finally, one of the challenges in web development is aligning the composability of our architecture and presentation layer with the content they manage. A well-designed composable system should not only consider the technical aspects but also take into account the nature of the content it handles. To help us with that, we can use a Headless Content Management system such as Storyblok.

Storyblok: Headless CMS With A Composable Approach #

Storyblok is a Headless Content Management System with many features and capabilities that help content editors, marketers, and other types of users to create and manage content efficiently. The content created with Storyblok (or any Headless CMS) can be presented in any way, as these platforms don’t force the developers to use a particular presentation layer logic.

Storyblok
Storyblok allows you to create and reuse content structures. You can even create and nest components without limits, fill them with content, and customize them to your needs. (Large preview)

The advantage of Storyblok, speaking about composability, is the component approach it uses to manage the content structures. Because of its Headless nature, Storyblok allows you to use the created components (or “blocks”, as they are called on the platform) with any technology or framework. Linking to the previous topic, you can create component structures to manage content in Storyblok while managing their visual representation with React components on the client-side (or server-side) of your application.

Conclusion #

Composability is a powerful paradigm that transforms the way we approach web development. By fostering modularity, reusability, and adaptability, a composable architecture lays the groundwork for building robust and scalable web applications. As we navigate through both server and client sides, aligning with content management, developers can harness the full potential of composability in order to create a cohesive and efficient web development ecosystem.

Wednesday, June 21, 2023

Visual Editing Comes To The Headless CMS

 Visual editing is beginning to make its way into headless architecture and the early results look promising. We’ll look at a few headless CMSs that currently support visual editing in this article.

A couple of years ago, my friend Maria asked me to build a website for her architecture firm. For projects like this, I would normally use a headless content management system (CMS) and build a custom front end, but this time I advised her to use a site builder like Squarespace or Wix.

Why a site builder? Because Maria is a highly visual and creative person and I knew she would want everything to look just right. She needed the visual feedback loop of a site builder and Squarespace and Wix are two of the most substantial offerings in the visual editing space.

In my experience, content creators like Maria are much more productive when they can see their edits reflected on their site in a live preview. The problem is that visual editing has traditionally been supported only by site-builders, and they are often of the “low” or “no” code varieties. Visual editing just hasn’t been the sort of thing you see on a more modern stack, like a headless CMS.

Fortunately, this visual editing experience is starting to make its way to headless CMSs! And that’s what I want to do in this brief article: introduce you to headless CMSs that currently offer visual editing features.

But first…

What Is Visual Editing, Again?

Visual editing has been around since the early days of the web. Anyone who has used Dreamweaver in the past probably experienced an early version of visual editing.

Dreamweaver circa 2005

Visual editing is when you can see a live preview of your site while you’re editing content. It gives the content creator an instantaneous visual feedback loop and shows their changes in the context of their site.

There are two defining features of visual editing:

  • A live preview so content creators can see their changes reflected in the context of their site.
  • Clickable page elements in the preview so content creators can easily navigate to the right form fields.

Visual editing has been standard among no-code and low-code site-builders like Squarespace, Wix, and Webflow. But those tools are not typically used by developers who want control over their tech stack. Fortunately, now we’re seeing visual editing come to headless CMSs.

Visual Editing In A Headless CMS

A headless CMS treats your content more like a database that’s decoupled from the rendering of your site.

Until recently, headless CMSs came with a big tradeoff: content creators are disconnected from the front end, making it difficult to preview their site. They can’t see updates as they make them.

A typical headless CMS interface just provides form fields for editing content. This lacks the context of what content looks like on the page. This UX can feel archaic to people who are familiar with real-time editing experiences in tools like Google Docs, Wix, Webflow, or Notion.

Fortunately, a new wave of headless CMSs is offering visual editing in a way that makes sense to developers. This is great news for anyone who wants to empower their team with an editing experience similar to Wix or Squarespace but on top of their own open-source stack.

Let’s compare the CMS editing experience with and without visual editing on the homepage of Roev.com.

Content editing with visual editing enabled
Content editing without visual editing; the experience of a typical headless CMS

You can see that the instant feedback from the live preview combined with the ability to click elements on the page makes the visual editing experience much more intuitive. The improvements are even more dramatic when content is nested deep inside sections on the page, making it hard to locate without clicking on the page elements.

Headless CMSs That Support Visual Editing

Many popular headless CMS offerings currently support visual editing. Let’s look at a few of the more popular options.

Tina

TinaCMS was built from the ground up for visual editing but also offers a “basic editing” mode that’s similar to traditional CMSs. Tina has an open-source admin interface and headless content API that stays synced with files in your Git repository (such as Markdown and JSON).

Storyblok

Storyblok is a headless CMS that was an early pioneer in visual editing. Storyblok stores your content in its database and makes it available via REST and GraphQL APIs.

Visual Editing with Storyblok

Sanity.io (via their iframe plugin)

Sanity is a traditional headless CMS with an open-source admin interface. It supports visual editing through the use of its Iframe Pane plugin. Sanity stores your content in its database and makes it available via API.

Builder.io

Builder.io is a closed-source, visual-editing-first headless CMS that stores content in Builder.io’s database and makes it available via API.

Visual Editing with Builder

Stackbit

Stackbit is a closed-source editing interface that’s designed to be complementary to other headless CMSs. With Stackbit, you can use another headless CMS to store your content and visually edit that content with Stackbit.

Vercel 

Although it’s not a CMS, Vercel’s Deploy Previews can show an edit button in the toolbar. This edit button overlays a UI that helps content creators quickly navigate to the correct location in the CMS.

Conclusion

Now that developers are adding visual editing to their sites, I’m seeing content creators like Maria become super productive on a developer-first stack. Teams that were slow to update content before switching to visual editing are now more active and efficient.

There are many great options to build visual editing experiences without compromising developer-control and extensibility. The promise of Dreamweaver is finally here!

Monday, April 3, 2023

Building Future-Proof High-Performance Websites With Astro Islands And Headless CMS

 Let’s see how to achieve phenomenal web performance and great developer experience with Astro and a headless CMS, resulting in the best possible experience for users, developers and content creators alike.

Nowadays, web performance is one of the crucial factors for the success of any online project. Most of us have probably experienced the situation that you left a website due to its unbearable slowness. This is certainly frustrating for a website’s user, but even more so for its owner: in fact, there is a direct correlation between web performance and business revenue which has been corroborated time and again in a plethora of case studies.

As developers, optimizing web performance must therefore be an integral part of our value proposition. However, before moving on, let’s actually define the term. According to the MDN Web Docs, “web performance is the objective measurement and perceived user experience of a website or application”. Primarily, it involves optimizing a site’s initial overall load time, making the site interactive as soon as possible, and ensuring it is enjoyable to use throughout.

Achieving an excellent measurable performance as well as an outstanding perceived performance certainly constitutes a potentially very strenuous challenge for developers, especially when dealing with increasingly complex, large-scale websites. Fortunately, while it is easy to get lost in the subtle details of performance optimization measures, there are a few factors that should be the focus points of our efforts due to their extraordinarily high impact. One of these is image optimization, a topic that has been thoroughly covered in ‘A Guide To Image Optimization On Jamstack Sites’ by my colleague Alba Silvente.

Another key factor? Shipping less JavaScript (JS). A large JS bundle size takes longer to be transmitted, parsed, and executed. As a consequence, the initial page load and Time to Interactive can be delayed quite significantly. In recent years, we have witnessed the rise of extremely powerful JS frontend frameworks that offer client-side rendering and strive for an app-like experience. While their versatility, their features, and their developer experience is impressive by all means, they all share one major disadvantage in regard to performance optimization: their JS bundle size is comparably heavy, negatively impacting both the initial page load and the time-to-interactive quite substantially.

Depending on the type of your project, the question arises whether a less JS-centric approach might be feasible. In fact, if you think of your average content-driven marketing website, you would probably conclude that only a fraction of the functionality actually relies on JavaScript, whereas the majority of the site could probably be rendered as static HTML.

And that is precisely where Astro enters the game, shipping zero JS by default and letting you partially hydrate only those components that de facto rely on interactivity. Importantly, Astro accomplishes all of that without sacrificing the wonderful developer experience (DX) that we have been getting spoiled by, but actually even improving it. Let’s take a closer look.

Introducing Astro

Astro defines itself as an “all-in-one web framework for building fast, content-focused websites”. One of its key features is that it replaces unused JS with HTML on the server, effectively resulting in zero JavaScript runtime out-of-the-box. This, in turn, leads to very fast load times and quicker interactivity. Notably, Astro explicitly states that it is specifically designed for content-driven websites, such as marketing, documentation, or eCommerce sites. The Astro team transparently acknowledges that other frameworks may be a much better fit if your project classifies as a web application rather than a mostly content-driven site.

Moreover, Astro provides a powerful Islands architecture that utilizes the technical concept of partial hydration. In a nutshell, this allows you to hydrate only those components that you actually need to be interactive. Importantly, this happens in isolation, leaving the rest of the site as static HTML. All in all, the impact on web performance is huge, making developers’ lives a lot easier along the way. And it gets even better: it is possible to bring your own framework. Thus, you could effortlessly use, for example, Vue, Svelte or React components in your Astro project.

Speaking of isolated islands, it is worth pointing out that developers actually rarely work alone: most larger-scale web projects typically rely on close collaboration between teams of developers and content creators. Therefore, let’s explore how going Headless with Storyblok can improve the experience and productivity of everyone involved.

Introducing Storyblok #

Storyblok is a powerful headless CMS that meets the requirements of developers and content creators alike. Completely framework-agnostic, you can connect Storyblok and your favorite technology within minutes. Storyblok’s Visual Editor allows you to create and manage your content with ease, even when dealing with complex layouts. Furthermore, localizing and personalizing your content becomes a breeze. Beyond that, Storyblok’s API-first design allows you to create outstanding cross-platform experiences.

Let’s explore in a case study how we can effectively combine the power of Astro and Storyblok.

Case Study: Interactive Components In Storyblok And Astro

In this example, we will create a simple landing page consisting of a hero component and a tabbed content component. Whereas the former will be a basic Astro component, the latter will be rendered as a dynamic island. In order to demonstrate the flexibility of this technology stack, we will examine how to render the tabbed content component using both Vue and Svelte.

This is what we will build:


Step 1: Create The Astro Project And The Storyblok Space

Once we’ve created an account on Storyblok (the Community plan is free forever), we can create a new space.


Now, we can copy and run the command to run Storyblok’s CLI in order to quickly create a project that is connected to your fresh new space:

npx @storyblok/create-demo@latest --key <your-access-token>

You can copy the complete command, including your personal access token, from the Get Started section of your space:


In the scaffolding steps, choose Astro, the package manager of your choice, the region of your space, and a local folder for your project. Now, in your chosen folder, you can run npm install && npm run dev to install all dependencies and launch the development server.

For the Storyblok Visual Editor to work, we need to go to Settings > Visual Editor and specify https://127.0.0.1:3000/ as the default environment.

Next, let’s go to the Content section and open our Home story. Here, we need to open the Entry configuration and set the Real path to / in order for src/pages/index.astro to be able to load this story correctly.

After having saved, you should now see the page being rendered correctly in the Visual Editor.

Perfect, we’re ready to move on.

Step 2: Create The Hero Component In Storyblok

In the Block Library, which you can easily access from within your Home story, you will find four default components. Let’s delete all of the nestable blocks (Grid, Teaser, and Feature). For our case study, we just need the Page content type block.

Note: In order to learn more about nestable and content type blocks, you can read the Structures of Content tutorial.

Now, we can create the first component that we will need for our case study: A nestable block called Hero (hero) and the following fields:

  • caption (Text)
  • image (Asset > Images)

Next, close the Block Library, delete the instances of the Teaser and Grid blocks, and create a Hero, providing any caption and image of your choice.

Step 3: Create The Hero Component In Astro

The next step is to create a matching counterpart for our Hero component in our Astro project. Let’s open up the project.

First of all, let’s modify astro.config.mjs in order to register our Hero component properly:

storyblok({
  accessToken: '<your-access-token>', // ideally, you would want to use an environment variable for the token
  components: {
    page: 'storyblok/Page',
    hero: 'storyblok/Hero',
  },
})

Next, let’s delete the Grid, Feature and Teaser components in src/storyblok and create a new src/storyblok/Hero.astro component with the following content:

---
import { storyblokEditable } from '@storyblok/astro'

const { blok } = Astro.props
---

<section
  {...storyblokEditable(blok)}
  class='relative w-full h-[50vh] min-h-[400px] max-h-[800px] flex items-center justify-center'
>
  <h2 class='relative z-10 text-white text-7xl'>{blok.caption}</h2>
  <img
    src={blok.image?.filename}
    alt={blok.image?.alt}
    class='absolute top-0 left-0 object-cover w-full h-full z-0'
  />
</section>

Having taken care of that, the Hero block should now be displayed correctly in your Home story. In this particular case, we are using a native Astro component, which means that this component will be rendered as static HTML, requiring zero JS!

Amazing, but what happens if you actually need interactivity on your frontend? This is precisely where dynamic islands come into play, which we will explore next.

Step 4: Create The Tabbed Content Component In Storyblok

Let’s proceed by creating the blocks that we need for our tabbed content component, which will have a slightly more complex setup.

First of all, we want to create a new nestable block Tabbed Content Entry (tabbed_content_entry) with the following fields:

  • headline (Text)
  • description (Textarea)
  • image (Asset > Images)

This nestable block will be used in superordinate nestable block called Tabbed Content (tabbed_content) consisting of these fields:

  • entries (Blocks > Allow only tabbed_content_entry components to be inserted)
  • directive (Single-Option > Source: Self) with the key-value pair options: load → load and idle → idle, and visible → visible (Default: idle)

The entries field is used to allow nesting of the previously created Tabbed Content Entry nestable blocks. In order to prevent any kind of block could get inserted, we can limit it to blocks of the type tabbed_content_entry.

Additionally, the directive field is used to take advantage of Astro’s client directives, which determine if and when a framework component should be hydrated. Utilizing the single-option field type in Storyblok enables content creators to choose whether this particular instance of the component should be hydrated with the highest priority (load), after the initial page load has been completed (idle), or as soon as the component instance actually enters the viewport (visible).

Utilizing Astro’s visible directive would result in the biggest performance gain as long as the component is below the fold. As the default option, we will use Astro’s idle directive, hydrating the component immediately on page load. However, in all cases, the rest of our landing page will remain as static HTML. As a result, the out-of-the-box performance should theoretically always be superior when compared to alternative frameworks.

Before moving on, we can use our newly created Tabbed Content component and insert three example entries in the entries field.

Step 5: Create The Tabbed Content Component In Astro #

First of all, let’s register our Tabbed Content component in our astro.config.mjs:

storyblok({
  accessToken: '<your-access-token>',
  components: {
    page: 'storyblok/Page',
    hero: 'storyblok/Hero',
    tabbed_content: 'storyblok/TabbedContent',
  },
}),

Next, let’s create storyblok/TabbedContent.astro with the following preliminary content:

---
import { storyblokEditable } from '@storyblok/astro'

const { blok } = Astro.props
---

<section {...storyblokEditable(blok)}></section>

This will serve as our wrapper component, wherein we can subsequently import the actual component using the UI framework of our choice and dynamically assign a client directive derived from the value we receive from Storyblok.

Step 6: Render the Tabbed Content Component using Vue 

With everything in place, we can now start building our tabbed content component using Vue. First, we need to install Vue in our project. Fortunately, Astro makes that very simple for us. All we have to do is to run the following command:

npx astro add vue

Next, let’s create a new Vue component (storyblok/TabbedContent.vue) with the following content:

<script setup lang="ts">
import { ref } from 'vue'
const props = defineProps({ blok: Object })

const activeTab = ref(0)

const setActiveTab = (index) => {
  activeTab.value = index
}

const tabWidth = ref(100 / props.blok.entries.length)
</script>

<template>
  <ul class="relative border-b border-gray-900 mb-8 flex">
    <li
      v-for="(entry, index) in blok.entries"
      :key="entry._uid"
      :style="'width:' + tabWidth + '%'"
    >
      <button
        @click.prevent="setActiveTab(index)"
        class="cursor-pointer p-3 text-center"
        :class="index === activeTab ? 'font-bold' : ''"
      >
        {{ entry.headline }}
      </button>
    </li>
  </ul>
  <section
    v-for="(entry, index) in blok.entries"
    :key="entry._uid"
    :id="'entry-' + entry._uid"
  >
    <div v-if="index === activeTab" class="grid grid-cols-2 gap-12">
      <div>
        <p>{{ entry.description }}</p>
        <a
          :href="entry.link?.cached_url"
          class="inline-flex bg-gray-900 text-white py-3 px-6 mt-6"
          >Explore {{ entry.headline }}</a
        >
      </div>
      <img :src="entry.image?.filename" :alt="entry.image?.alt" />
    </div>
  </section>
</template>

<style scoped>
ul:after {
  content: '';
  @apply absolute bottom-0 left-0 h-0.5 bg-gray-900 transition-all duration-500;
  width: v-bind(tabWidth + '%');
  margin-left: v-bind(activeTab * tabWidth + '%');
}
</style>

Finally, we can import this component in TabbedContent.astro, pass the whole blok object as a property and assign the client directive based on the value we receive from Storyblok.

---
import { storyblokEditable } from '@storyblok/astro'
import TabbedContent from './TabbedContent.vue'

const { blok } = Astro.props
---

<section {...storyblokEditable(blok)} class='container py-12'>
  {blok.directive === 'load' && <TabbedContent blok={blok} client:load />}
  {blok.directive === 'idle' && <TabbedContent blok={blok} client:idle />}
  {blok.directive === 'visible' && <TabbedContent blok={blok} client:visible />}
</section>

Furthermore, our Astro wrapper component is the right place to assign a client directive to the Vue component. Since we would like to give the content creators the possibility to choose between different directives, we need to assign them based on the value we retrieve from Storyblok.

Our tabbed content component will now be rendered correctly. Using Astro’s dynamic islands and hydration directives can tremendously boost your site’s performance, and combined with Storyblok, you provide content creators with straightforward and easy-to-use possibilities to tap into the power of this next-gen approach.

Let’s conclude our case study by examining how to render the very same component with Svelte (or any other popular framework supported by Astro).

Step 7: Render The Tabbed Content Component Using Svelte #

First of all, as before, we need to install Svelte in our Astro project. Again, we can easily accomplish that by running the following command:

npx astro add svelte

Now, we can create the Svelte component (storyblok/TabbedContent.svelte) with the following content:

<script>
  export let blok

  let tabWidth = 100 / blok.entries.length
  let activeTab = 0
  let marginLeft = 0

  const setActiveTab = (index) => {
    activeTab = index
    marginLeft = activeTab * tabWidth
  }
</script>

<ul
  class="relative border-b border-gray-900 mb-8 flex"
  style="--tab-width: {tabWidth}%; --margin-left: {marginLeft}%;"
>
  {#each blok.entries as entry, index (entry._uid)}
    <li style="width: var(--tab-width)">
      <button
        class="{index === activeTab
          ? 'font-bold'
          : ''} w-full cursor-pointer p-3 text-center"
        on:click={() => setActiveTab(index)}>{entry.headline}</button
      >
    </li>
  {/each}
</ul>
{#each blok.entries as entry, index (entry._uid)}
  {#if index === activeTab}
    <section id={entry._uid}>
      <div class="grid grid-cols-2 gap-12">
        <div>
          <p>{entry.description}</p>
          <a
            href={entry.link?.cached_url}
            class="inline-flex bg-gray-900 text-white py-3 px-6 mt-6"
            >Explore {entry.headline}</a
          >
        </div>
        <img src={entry.image?.filename} alt={entry.image?.alt} />
      </div>
    </section>
  {/if}
{/each}

<style>
  ul:after {
    content: '';
    @apply absolute bottom-0 left-0 h-0.5 bg-gray-900 transition-all duration-500;
    width: var(--tab-width);
    margin-left: var(--margin-left);
  }
</style>

The only change that we have to make in order to load the Svelte component instead of the Vue component can easily be completed by simply changing the import in TabbedContent.astro:

//import TabbedContent from './TabbedContent.vue'
import TabbedContent from './TabbedContent.svelte'

And that’s it! Everything else can remain the same. Amazingly, our tabbed content component still works but is now using Svelte instead of Vue. Since Astro makes it possible to pass down the blok object, containing all of the data coming from Storyblok, as a property to the different framework components, we can simply reuse all of the information in various environments.

Wrapping Up

With Astro, you as a developer benefit from phenomenal DX, mind-blowing performance out of the box, and a high degree of flexibility thanks to the possibility to bring your own component framework (or even combine multiple component frameworks) and the availability of integrations. Moreover, Astro is highly future-proof: Considering moving from Vue to Svelte? From React to Vue? Astro makes the transition seamless, keeping the foundation of your project the same.

With Storyblok, your clients or fellow colleagues from the content marketing team get to enjoy a high degree of autonomy and flexibility, effectively utilizing the full potential of your Astro code base. Landing pages can be created in a matter of mere minutes, and dynamic, interactive components will have no negative impact on their performance.

Taking everything into account, Astro and Storyblok may very well be the last technology stack you will ever need for your content-driven website projects.