Introduction to Jahia JavaScript modules

May 25, 2024

Overview of a JavaScript module

JavaScript modules are available as an alpha version starting with Jahia 8.2, and tutorials are available in the Get Started section!

What is a JavaScript module?

A JavaScript module is a way to build websites with Jahia. It uses the NPM packaging project structure and JSX/React. It allows you to package up page templates, content views, settings, labels, and more and deploy them on a Jahia DXP.

Note: A JavaScript module is an alternative to Jahia’s OSGi-based Java modules. Although Jahia is a Java-based server, JavaScript modules require no knowledge of Java and do not require any Java code. Developers with frontend or server-side JavaScript experience can quickly start building Jahia JavaScript modules.

JavaScript modules are structured the same way as any NodeJS project and are centered around a package descriptor JSON file named package.json

JavaScript modules may contain:

  • Content type definitions (CND)
  • Page and content template scripts (React Server-Side Rendering JSX)
  • Content view scripts (React Server-Side Rendering JSX)
  • Static resources (text files, images, CSS files, and JavaScript files)
  • Labels (aka Resource bundles or Locale files)
  • More advanced resources, such as permissions or rules

The package.json file contains dependencies to other npm packages that are the project's dependencies, essentially libraries used by the current project. The package.json file can have two types of dependencies: devDependencies and regular (runtime) dependencies. The devDependencies are only used to build the project and will not be used when resolving dependencies for other projects using the current package.

Rendering Jahia CMS content with Javascript modules

To understand the concepts used when rendering with JavaScript modules in the Jahia CMS, let’s look at a typical representation of how the different elements are used and how they relate to each other.

JavaScript modules use React Server Side Rendering as a rendering technology. To learn more about this, please consult our dedicated section, which explains it in detail.

The Page content type

As explained in the concepts, a page in Jahia is a built-in content type with the following simplified definition:

[jnt:page] > nt:base, jmix:navMenuItem
 orderable
 - jcr:title (string) i18n mandatory boost=2.0
 - j:templateName (string, choicelist[templatesNode]) mandatory nofulltext
 - j:isHomePage (boolean) hidden
 + * (nt:base) = nt:base version
 + * (jmix:navMenuItem)    

In the above definition, you will note that a page:

  • Inherits from the jmix:navMenuItem type that may also include sub-nodes of that same type. This technique is how the page navigation tree is built.
  • It has a j:templateName property that references the name of a page template and is user-selectable. This means that when creating a page, a user can select the template among the available ones and which one he wants to use for his page.

Page Templates

A template script produces the HTML page by delegating rendering to sub-elements such as views and components. A template might include:

  • HTML tags such as the <head> and <body> tags,
  • the necessary page metadata or resources (CSS, JavaScript) for that specific layout, using the AddRessources component
  • React components to include other components or content views.

For example, a page template might include a Hero or an Area view, as illustrated above.

In JavaScript modules, page templates are implemented using JSX scripts. Here is an example of a page template named home :

import React from 'react';
import {Area, AddResources} from '@jahia/js-server-core';

export const PageHome = () => {
    return (<>
        <head>
            <AddResources type='css' resources='styles.css' />
            <title>Home</title>
        </head>
        <body>
            <h1>Home Template</h1>
            <main>
                <Area name="pagecontent" />
            </main>
        </body>
    </>);
}

PageHome.jahiaComponent = { // This object is used to register the template in Jahia
    nodeType: 'jnt:page', // The content node type the template applies to
    name: 'home', // The name of the template
    displayName: 'Home page', // The display name of the page template
    componentType: 'template' // the component type is set to template (as opposed to view component types)
}
    

Let’s break down the elements of this template script:

  • Import section:
    • react: The core React library
    • @jahia/js-server-core: Jahia npm library providing all kinds of utilities for interacting with Jahia core
  • HTML section
    • As you can see, in the above example, the page template includes the <head> and <body> tags.
    • Uses other React components to include CSS files
    • An Area component that will make it possible for content authors to include any content they desire.
  • jahiaComponent: At the bottom of the page template is the template registration information, including:
    • nodeType: the node type used to register the template: for page templates, it’s always: jnt:page
    • name: used as a unique identifier for the page template
    • displayName: will be displayed to the content authors when they create a page and can choose a page template
    • componentType: that may be either a template or a view.

Content templates

Another type of template also exists in Jahia: content templates. For example, if a page template displays a list of blog articles using views, we can use a content template to display a blog article on a full page and insert a link to this rendering in the list.

This full-page display will include all the usual elements found in a page template, such as a header and footer, navigation as well as CSS and JavaScript resources.

  • The import section would be very similar to a page template
  • The HTML section would also be similar, with one addition: it would typically include the following instruction to render the content of a blog article:
<Render node={currentNode} view="fullPage"/>    

Where:

  • Render component is a Jahia built-in component to render content using a view
  • node parameter: When using a content template, the content being displayed (the blog article) will be available as currentNode
  • view parameter: the name of the view to use, as defined in the jahiaComponent
  • The jahiaComponent declaration would look like this:
BlogDefault.jahiaComponent = {
    nodeType: ‘acme:blog’,
    name: 'fullPage',
    componentType: 'template'
};    

Usually, in conjunction with a content template, a full-page view of the content object is also developed.

Views and content type definitions

Views are a way to transform the content from a content node into HTML. A view is a script that will render the content from the Jahia CMS content node and define how it will be included in the HTML output. Here is an example of a simple view for a hello content node type:

import React from 'react'
import { useServerContext, getNodeProps } from '@jahia/js-server-core'

export const HelloDefault = () => {
    const { currentNode } = useServerContext();
    const props = getNodeProps(currentNode, ['textHello']);
    return (
        <div>
            <h2>{props.textHello}</h2>
        </div>
    )
}

HelloDefault.jahiaComponent = { // this object is used to register the view in Jahia
    nodeType: 'example:hello', // The content node type the template applies to
    displayName: 'Hello (default)', // The display name of the view
    componentType: 'view' // the component type is set to view (as opposed to template component types)
}
    

As we can see in the above example, views are, by design, very close to templates in terms of actual implementation.

The above view is associated with a content type definition that we are showing here:

<jnt = 'http://www.jahia.org/jahia/nt/1.0'>
<example = 'http://www.acme.org/example/nt/1.0'>

[example:hello] > jnt:content
 - textHello (string) = 'Hello world !' i18n
    

The above definition defines a new content type called example:hello. It has a single property named textHello, which is an internationalized (i18n) string type with a default value of ‘Hello World !’.

A word on namespace: The example and jnt are namespace definitions that allow regrouping and avoid name clashes if multiple modules define the same name for a content definition. Each module should have its namespace definition. The jnt namespace is the default Jahia namespace, and we use it here because we are inheriting the jnt:content definition type, which is the basic definition type for all content objects.

While most views and content definitions are pretty straightforward, as in the previous example, some are more advanced such as navigation menu views, that will recursively render a tree of content objects. It is not necessary to master these advanced views, but it is just important to remember that this mechanism is central to the Jahia CMS rendering mechanism and will often be used.

Components

Components, or more specifically React components, are reusable pieces of rendering script logic that can be shared among views or event templates. Examples of components might include header and footer components, carousel components, or the Jahia built-in components to render resources (AddResources) and areas (Area & AbsoluteArea). The list of all components provided by Jahia can be found in the reference documentation.

Components are just standard React server-side components, which means that they must be able to render server-side, which implies that it is not possible to use events or any client-side specific hooks.

Here is an example of such a component :

import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
export const Table = ({rows = [], className}) => {
    return (
        <dl className={clsx('lux-table', className)}>
            {rows.map(row => (
                <div key={row.title} className="lux-table_row d-flex">
                    <dt className="lux-table_key">{row.title}</dt>
                    <dd className="lux-table_value">{row.value}</dd>
                </div>
            ))}
        </dl>
    );
};

Table.propTypes = {
    rows: PropTypes.arrayOf(
        PropTypes.shape({
            title: PropTypes.string.isRequired,
            value: PropTypes.string.isRequired
        })
    ).isRequired,
    className: PropTypes.string
};
    

Here is an example of how to use such a component in a view:

import { Table } from './Table';

const ExampleView = () => {
  // Example data to display in the table
  const userData = [
    { title: 'Name', value: 'John Doe' },
    { title: 'Email', value: 'john.doe@example.com' },
    { title: 'Age', value: '28' },
    { title: 'Location', value: 'New York, USA' }
  ];

  return (
    <div className="App">
      <h1>User Information</h1>
      <Table rows={userData} className="my-custom-table-class" />
    </div>
  );
};

    

As you can see, this is a standard React JSX component that simply makes it possible to pass it an array of rows and a className, and it will render an HTML description list (<dl>) based on the rows.

Understanding the build & the packaging

What is Yarn?

Yarn is an established open-source package manager who manages dependencies in JavaScript projects. It assists with installing, updating, configuring, and removing package dependencies. It is used by Jahia as the primary package manager for all of its projects. Yarn is used in conjunction with Webpack to build JavaScript modules.

What is WebPack?

Webpack bundles modern JavaScript apps, optimizing dependencies into faster-loading bundles. Launched via Yarn, it compiles assets like JavaScript, CSS, and SASS with Jahia's NPX project creator including default Webpack integration for varied project needs, even including client-side JavaScript bundling.

JavaScript module creation script

Jahia provides an NPM executable script (NPX) that can simplify the creation of a new module. Here is an example of its usage:

npx @jahia/create-module@latest solid-template jsx    

This example will create a new project named solid-template in the same-named directory and use the JSX project type (this is the only currently supported project type)

The general syntax for this script is:

npx @jahia/create-module@VERSION PROJECT_NAME PROJECT_TYPE    

Where:

  • @jahia/create-module is the name of the public package. You can find the package here: https://www.npmjs.com/package/@jahia/create-module
  • VERSION is the version of the script you want to use. In general, you should use latest as the version name, but you could also provide a specific version if you want to be sure that all your projects use the same one (as new ones may be published on https://www.npmjs.com/package/@jahia/create-module at any time).
  • The PROJECT_NAME could be any project name you want, but be careful that the project name will be used for the directory name as well as the namespace name throughout the generated project, so you should use something simple and only use “-” and “_” as special characters.
  • The PROJECT_TYPE should only be jsx, as other project types are not supported. Maybe future versions might introduce new types.

The project will generate some files and folders:

  • package.json: the JSON NPM package description
  • webpack.config.js: the Webpack configuration
  • src: the directory where all the source files are
  • definitions.cnd: the content type definition file
  • .env.example: the default example deployment configuration (see the section below)
  • Other folders: static asset folders

You may find details of the generated project structure here.

Yarn tooling

Jahia provides some useful out-of-the-box Yarn scripts when created using our NPX project starter tool. Here are some examples of using these tools.

To install all the project dependencies:

yarn    

To build a project (assuming the yarn command was previously executed):

yarn build    

To deploy a project (assuming the yarn build command was previously executed):

yarn deploy    

The deploy script also comes with a default configuration file (.env.example). To customize the configuration, you should copy the .env.example file to a .env file and modify it according to your needs. See the section below for information on how to change the configuration.

You can also combine these commands to build and deploy in a single command line:

yarn build && yarn deploy    

To watch a project (this script will build and deploy changes automatically!):

yarn watch
    

To package a project:

yarn jahia-pack    

Note: Yarn also has a pack command that Jahia does not support. It generates a package.tgz file that doesn’t contain the package’s name or the version. The jahia-pack command generates a .tgz file that contains both and is recommended for deployment on a Jahia server or just for exchanging with others.

Here is a reference table for all these scripts:

Script name Description
build build the project
deploy deploy the project. Make sure you have updated the .env file to match your setup if needed.
watch will build and watch for file modifications and deploy them automatically when changes are detected. Use CTRL+C to stop watching.
lint use to check that your code follows the recommended syntax guidelines. Append --fix to automatically fix most problems.
test to test your project. By default, it only performs yarn lint, but you are encouraged to add your own testing system here.
jahia-pack To generate a tgz file of the project that you can then manually deploy to a Jahia server. This script does not perform a build, so make sure the project is built before using this one. Note: avoid using the pack command, as it behaves differently
deploy To deploy a previously built and packed project to a Jahia server.

 

jahia-deploy configuration file (.env)

By default, the generated project will contain a .env.example file that contains the default configuration for the jahia-deploy script. It is recommended that you make a copy of this file using the name .env and then adjust it to your Jahia server configuration. Here is a table that references the configuration options

Variable Default value Description
JAHIA_USER username:password This variable contains the username and password of a user that has the permission to deploy modules on a Jahia server (usually the root user)
JAHIA_HOST http://localhost:8080 The URL of the Jahia server on which to deploy the project
JAHIA_DEPLOY_METHOD curl The jahia-deploy script supports two deployment methods: curl and docker. With the curl method, it will just need the JAHIA_HOST variable to point to the proper installation and it can work with remote installation. With the docker method, it will need a JAHIA_DOCKER_NAME variable to contain the name of a local docker container name. Remote docker deployments are not supported. In general, the curl method is the most powerful and flexible method.
JAHIA_DOCKER_NAME jahia The name of the local docker container to use to deploy the package