Welcome to Slingslop

Build web-applications on top of Apache Sling (+ htmx)

What is Sling, a CMS ?

No. It's an under-appreciated open-source framework for web-applications in general.
It's currently serving very large sites in form of Adobe Experience Manager (AEM), which is a CMS build on top of Sling.

Sling itself is quite abtract, it doesn't even know what a page is. It's all resources in an unstructured content-tree (JCR), some of them happen to get rendered as HTML. But it does not come with a built-in user interface. You need to code the frontend (HTML, CSS, JavaScript) on your own.

Due to its modularity, Sling consists of more than 300 modules. There is one for almost everything an "enterprise" application server needs. SchedulingEventing and JobsCluster Discovery and Distribution, Testing ecosystem, S3/Azure BlobstoreLogging, GraphQL ...

Chances are you don't need any of that; you can start simple.

Dealing with complexity

There is a bit of a learning curve to get started. Even the most simple project needs five modules:

  • Frontend build with TypeScript and CSS

  • HTML templates and components

  • Business-Logic: where things from the real-world get a name (the hard part) and become code

  • Content: the story to tell with text and images

  • Server: something that boots, creates a repository, installs all of the above and listens to incoming HTTP requests

This is intimidating at first, but we've get 'separation of concerns' from the start:
Designers, frontend and backend developers, editors and operations can work on the same project, in parallel, without stepping on each others toes. Regardless of the software stack, these concerns have to get adressed in every project — one way or the other.

What is Slingslop ?

The page you're readling right now is a Sling app, a static but editable MPA (Multi-Page Application, formerly known as website).
While Sling is perfectly capable of serving headless json-content for an SPA (Single-Page Application, yes there is a module for that too) we will focus on HDA (Hypermedia-Driven Application) driven by htmx.

Keep in mind that Sling can be used in all sorts of integrations. The architecture suggested here exemplifies the simplicity of both, Sling and htmx play together in way that makes one wonder how they do htmx with 'only static endpoints'. It's a great way of explaining the core-concept of Sling by coming from htmx. More on that later.

Slingslop is a project on github that showcases the complete setup. It's not software on it's own, just a plumbing-together of open-source pieces. The license allows you to copy everything for a quick start without the duty to keep your work open-source.

Inspired by the Sling community

Click here for history on this project

Experiments on this started after the adaptTo conference in 2019, where the Sling Feature Model 1.0 was revealed and two CMSs were presented: Composum Pages and Peregine CMS: "There is no CMS in Sling, now there are suddenly three that are open source". (Third one being Sling CMS presented in 2021).

In short, in combination it's possible to bake two CMSs into the same docker image, which is a silly thing to do but it makes a few important points:

  • about the application-serverness of Sling: the ability to host multiple complex apps. Side-note: Peregrine renders a vue SPA, completely breaking with AEM's traditional MPA style

  • about shared infrastucture:

    • Composum's JCR node-browser (similar to what /crx/de does in AEM)

    • a user-manager that also allows to set read/write permissions in JCR

    • a package-manager to up/download content zip-files, which in turn enables deployment of apps in the browser - instead of commandline or sling-feature-model

Technically these three tools are also "only" apps on top of Sling, but shipped with the official Sling Starter. Sling doesn't needs them, they just make live a bit easier.

CSS zengarden

The maven sling-project-archetype is a good starting point. For the above, only the launcher's feature-model was needed. CMSs were added there, using the Sling Feature Model, which is a higer level building block that offers an additional way of collaboration instead of fine grained modules.
The archetype also comes with an example app for new projects, but it's a plain 'Hello World' experience. How to make it look nice?
This was pre-AI, lacking frontent-skill the idea was to "borrow" around 20 styles from CSS Zen Garden: The Beauty of CSS Design from 2003, take it's oldschool HTML and replace static text by JCR content.

The only "Business-Logic" is to randomly select a design on every load, resulting in confusion. Designs predate smartphones, can't cope with longer texts, some overlay headlines with images. For editing or creating a new page you'd have to use the node-browser.

Apart from the separation of look&feel from content, some lessons can be learned for creating a Sling application from scatch:
Importing existing markup as Sightly script (aka HTL), split it up into includes and components, copy over the CSS, separate markup from text that is stored in JCR data.

Hypermedia-Driven Applications

In short, htmx (or datastar) enables developers to define dynamic behavior directly in markup. You click a button and some element changes.
In MPAs you click on an anchor-tag and load a new page's HTML. Which is fine, when css+js are properly cached. But the screen flickers a bit.

SPAs load data - usually JSON - and JavaScript modifies the element. Mainsteam web development (and unguided coding-agents) is mostly into SPAs: React, Angular, Vue, Svelte, SolidJS, Qwik, Preact, Lit, ... bringing in complexity. Next you'll need deeplinks (SPA after a few clicks) optimized for search-engines and end up rendering the HTML on the server again (SSR or hydration).

With HPAs the server returns HTML and the element gets replaced. That's it

<div hx-get="/api/greeting"
     hx-trigger="click"
     hx-swap="innerHTML">
Click me!
</div>

It's easy to understand - you look at the response and directly see what is added.

● Any element can issue HTTP requests
● Any event can trigger a request
● Server returns HTML, not JSON
● Swap the response into the DOM

In abstract terms, application-state shifts from the client to the server. This keeps the client simple but also dumb. It doesn't always makes sense to do a sever-call, so in practice you'll end up somewhere in the middle, only with less JavaScript. Just don't do SPA+htmx at the same time, SPA-frameworks often can't cope with changes outside the Shadow DOM.

Zen-editable without Java(Script)

Sling and htmx are a perfect match, because each element backed by a JCR node like a page or component already comes with endpoints out-of-the-box. So let’s get into Sling basics.

Have a look into JCR with node-browser, to understand how script-resolution works:

Sling script resolution component example
  1. Browser requests https://zengarden.motorbrot.org/home.html

  2. On that domain, webserver adds /content/slingslop/zengarden for short URLS (optional, not part of Sling)

  3. Sling maps URLs to JCR tree. The node ‘home’ has the property sling:resourceType ‘slingslop/zengarden/pages/homepage’, which finds the HTML template under /apps/slingslop…

  4. That template then renders subnodes: <div data-sly-resource="${'./intro/summary' />
    with markup fragment found by the same sling:resourceType mechanism under:
    /apps/slingslop/zengarden/components/intro/summary/summary.html

The component template looks like this and renders “the story”, in this case the property with the name ‘text’:

<div class="summary" id="zen-summary" role="article">
  ${properties.text @ context='html'}
</div>

Now let’s use SlingPostServlet to write.

Follow the White Rabbit

Follow the White Rabbit

Ready to see how deep the rabbit hole goes? Explore our documentation sections to unlock the secrets of Apache Sling:

  • OSGi - The modular foundation of the Matrix

  • JCR - The repository that stores all truth

  • Sling - The framework that brings it all together