How Does a Scrivito App Work?

For illustrating how a Scrivito-powered app works, we'll take a closer look at the Scrivito Example Application, a simple yet feature-rich JS web application for easily getting started with Scrivito.

Explore the app or use it as the basis of your own client-side JS website! Please refer to Getting Started with Scrivito or the Readme at GitHub for details on how to install and run the Example App locally.

What is Scrivito? 

The Scrivito CMS consists of two main components interacting with each other: a backend, which transparently manages your content, and a JavaScript library (the SDK) that acts as a content management layer in a web application based on React. React is Facebook's solution to building interactive web interfaces using self-contained components written in JavaScript. The Scrivito SDK utilizes React to access and render the content in your Scrivito CMS and also includes Scrivito's unparalleled user interface for managing content and editing it in place.

How page display starts rolling 

After setting up and launching the JS example app, it is served from the “src” directory of your local repository. However, the file initially served is “catch_all_index.html” from the “public” directory. Let's take a look at this file first:

public/catch_all_index.html
Copy
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="generator" content="Scrivito by Infopark AG (scrivito.com)">

  <title>Scrivito Example App JS</title>
  <link rel="preconnect" href="https://api.scrivito.com" crossorigin>
  <link rel="preconnect" href="https://api.scrivito.com">
  <link rel="stylesheet" href="/index.css">

  <script src="/js_snippets_head.js"></script>
</head>
<body>
  <div id="application">
    <span class="loader">Loading...</span>
  </div>
  <script src="/index.js"></script>
  <script src="/js_snippets_before_body_end.js"></script>
</body>
</html>

The <head> doesn’t contain anything special, except for the included “js_snippets_head.js” file. If, for example, your site makes use of one or several third-party services, provide the code that needs to be run in this file. Analogously, “js_snippets_before_body_end.js” is included in the <body>. It is for letting those services render additional markup, in case they need to.

Obviously, by default, the only visible part in the <body> of “catch_all_index.html” is a <div> element whose ID is “application”. Into this element everything a page consists of will be rendered by the “index.js” JavaScript file which is then loaded (from the “src” folder):

Copy
import 'globals';
import 'scrivito_sdk';
// More imports

ReactDOM.render(<App />, document.getElementById('application'));

The call to “ReactDOM.render” does exactly that. It renders a thing named “App” into the “application” DOM element mentioned above.

As you might have guessed, “App” is a function contained in “App.js”. It displays a page by generating a navigation and rendering the contents of the current page. In case the latter cannot be determined, an appropriate error message is displayed.

Let’s take a closer look at the “App” function.

What is the current page?

“App” renders the current page by calling the Scrivito.CurrentPage React component built into Scrivito.

Initially, the current page is the homepage contained in your CMS. As the visitor navigates the website, the current page changes.

Now, at startup, how does Scrivito.CurrentPage know which object in your CMS is the homepage?

src/App.js
Copy
export default function App() {
  return (
    <ErrorBoundary>
      <div>
        <div className="content-wrapper">
          <Navigation />
          <Scrivito.CurrentPage />
          <NotFoundErrorPage />
        </div>
        <Footer />
        <GoogleAnalytics />
        <CurrentPageMetaData />
        <Intercom />
      </div>
    </ErrorBoundary>
  );
}
To find the homepage at startup time and render it, <Scrivito.CurrentPage /> determines the  CMS object whose path is “/”. As the visitor browses the website, the page to become the current page is identified by the CMS object's id contained in the linked URL.

Show me the page!

With Scrivito, all content in your CMS is stored in attributes of CMS objects. To be able to have different types of objects (e.g. homepages, landing pages, blog posts), you can define object classes (models) and provide them with a set of attributes of your choice.

To get an overview of the object classes the Scrivito example application is equipped with, let's take another look at the project directory, this time at the “src/Objs” folder.

The individual page types defined for a Scrivito app are represented as folders named after them. Each folder contains up to three JavaScript files, one for the model class (e.g. “HomepageObjClass.js”), one for the component that renders its instances, and one for configuring how attributes are presented to editors when they edit the properties of a CMS object. This analogously applies to the widget types in the “Widgets” directory.

Next to various page types, there is one for images, too. If you open the “ImageObjClass.js” file in the “Image” folder, you can see that image objects are regular CMS objects, meaning that they can be given attributes.

Copy
const ImageWidget = Scrivito.provideWidgetClass('ImageWidget', {
  attributes: {
    image: 'reference',
    alignment: ['enum', { values: ['left', 'center', 'right'] }],
    alternativeText: 'string',
    link: 'link',
  },
});

export default ImageWidget;

Displaying CMS content is rendering attributes

Now, back to pages and how they are rendered. First, all content is rendered by the React component that has been provided for the instances of an object class, i.e. the pages of a specific type. Second, all pages whose content is meant to be editable usually have an attribute of the widgetlist type. In the Scrivito example app, it's named body, but you can name it whatever suits best. It is this widgetlist attribute into which the main content of a page goes: the widgets an editor chooses to place on the page.

So, displaying a page breaks down to rendering the parts common to all pages of that type (header, navigation, footer) plus the widgets contained in the body attribute. All the React component needs to do is render this attribute:

Copy
Scrivito.provideComponent('Homepage', ({ page }) =>
  <Scrivito.ContentTag tag="div" content={ page } attribute="body" />
);

This causes the contents of the body widgetlist to be rendered by the widgets’ corresponding React components. Let's look into the “src/Widgets” folder of the Scrivito example app directory.

Making attributes editable

Scrivito comes with a considerable amount of widget types you are free to customize and extend. As with object classes, widget classes define the attributes of their instances, and for rendering them, a React component is required.

Most widgets have properties that cannot be edited in place. The image widget of the example application, for instance, lets you specify the alignment via the equally named attribute. For making it editable on every image widget's properties dialog, the model class can be associated with a configuration using Scrivito.provideEditingConfig:

Copy
// src/widgets/ImageWidget/ImageWidgetEditingConfig

Scrivito.provideEditingConfig('ImageWidget', {
  title: 'Image',
  thumbnail: `/${imageWidgetIcon}`,
  attributes: {
    alignment: {
      ...
    },
    alternativeText: {
      ...
    },
    link: {
      ...
    }
 },
  properties: [
    ...
  ],
  initialContent: {
    alignment: 'left',
  },
});

Other components of the example application

Some components of the example application have been placed into directories underneath “src”, either to keep the app structure clear, or because they are used in several places, or both. The “Components” directory, for example contains the React components for the navigation, the footer, things related to blogposts and other fragments needed on the pages. The “utils” directory is for little helpers, and the “assets” and “config” directories contain just that.

Do you find the Example App useful? Contact us if you need help or advice or would like to give us some feedback!