Integrating a static HTML template

May 23, 2024

Overview

To integrate an HTML template (e.g. the delivery of a web agency) you will need to go through five steps:

  1. Retrieve the original HTML source code
  2. Create a new JavaScript project
  3. Copy static resources from the HTML source code to the JavaScript project
  4. Copy and transform the HTML to become a JSX component
  5. Register your component so the Jahia template service may recognize it

Downloading the original template

For this tutorial, we will use an HTML site template from cruip.com: https://cruip.com/solid/

Download the template by clicking the DOWNLOAD button on the above-linked page (or use this link if for some reason it doesn’t work for you) and uncompress the ZIP file in a directory we will reference as $HTML_TEMPLATE from now on. You can also simply set an environment variable to that directory so that all the upcoming commands will work transparently:

Linux/macOS: export HTML_TEMPLATE=FULL_PATH_TO_HTML_TEMPLATE_DIRECTORY
Windows: setx HTML_TEMPLATE "FULL_PATH_TO_HTML_TEMPLATE_DIRECTORY"     

An easy way to make sure you are using the full path is to use the following trick:

cd solid
export HTML_TEMPLATE=`pwd`
cd ..    

Be careful in the export template command these are not quotes but backtick characters

Create a new project using our NPM @jahia/create-module starter template utility:

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

The previous command creates a project name solid-template (in the solid-template directory) and it will use the JSX file format to generate all the components. What this means is that all rendering will use server-side React rendering technology (also known as React SSR).

The generated structure will look like this:

css/ <- put here all CSS to be available publicly
images/ <- put here all images to be available publicly
javascript/ <- put here any client-side JavaScript
src/server/views/[nodeType]/NodeTypeAndViewName.jsx <- node type views
src/server/templates/page/PageAndTemplateName.jsx <- page templates
src/server/templates/[nodeType]/NodeTypeAndTemplateName.jsx <- content templates
src/server/components/header.jsx <- React SSR generic components
definitions.cnd <- node type definitions
resources/module-name.properties<- Java resourcebundles
webpack.config.js <- Webpack configuration
package.json <- NPM project descriptor
    

We will now refer to the solid-template directory as $NPM_TEMPLATE. You can also set an environment variable to this directory with the following command:

Linux/macOS: export NPM_TEMPLATE=FULL_PATH_TO_SOLID_TEMPLATE_NPM_PROJECT
Windows: setx NPM_TEMPLATE "FULL_PATH_TO_SOLID_TEMPLATE_NPM_PROJECT"    

Or could also simply do on Linux/macOS:

cd solid-template
export NPM_TEMPLATE=`pwd`
cd ..
    

Make sure you use full paths for both environment variables and not relative ones otherwise you might encounter some issues. You can get the full path of your directory by using the pwd command.

Initializing the project and auto-completion

We will now initialize the project and download all the dependencies so that auto-completion may work properly. You can do so with the following command:

cd solid-template
yarn    

For Visual Studio Code users

There are some additional steps for Visual Studio Code users to get auto-completion to work properly when using Yarn V4:

  • Install the ZipFS extension, which is maintained by the Yarn team.
  • Run the following command, which will generate a .vscode/settings.json file:
yarn dlx @yarnpkg/sdks vscode    
  • Normally Visual Studio Code should automatically suggest that you use the workspace version but if it doesn’t you can explicitly activate it using the following steps:
    • Press CTRL+SHIFT+p(Windows/Linux) or OPTION+SHIFT+P(macOS) in any file
    • Choose "Select TypeScript Version"
    • Pick "Use Workspace Version"


Your VSCode project is now configured to use the exact same version of TypeScript as the one you usually use, except that it will be able to properly resolve the type definitions.

It is recommended that you restart VS Code to make sure that the Typescript server starts properly. You can verify its status in the “Output” panel by selecting “Typescript”. You should see something like this:

Copying static resources

Then let's copy all the images from the $HTML_TEMPLATE/dist/images directory to the $NPM_TEMPLATE/images directory:

Linux/macOS: cp -rf $HTML_TEMPLATE/dist/images/* $NPM_TEMPLATE/images
Windows: Copy-Item -Path "$env:HTML_TEMPLATE\dist\images" -Destination "$env:NPM_TEMPLATE" -Recurse -Force    

Next let’s do the same thing for the CSS files:

Linux/macOS: cp -rf $HTML_TEMPLATE/dist/css/* $NPM_TEMPLATE/css
Windows: Copy-Item -Path "$env:HTML_TEMPLATE\dist\css" -Destination "$env:NPM_TEMPLATE" -Recurse -Force    

Finally let’s copy the JavaScript code:

Linux/macOS: cp -rf $HTML_TEMPLATE/dist/js/* $NPM_TEMPLATE/javascript
Windows: Copy-Item -Path "$env:HTML_TEMPLATE\dist\js" -Destination "$env:NPM_TEMPLATE" -Recurse -Force

Quick overview of JSX page template format

The src/server/templates/page/PageHome.jsx was created by npx and contains the following code:

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)
}    

The PageHome.jsx is a page template that is called ‘home’ and that is used to display the home page created when we create a site using the template set we are now building.

Converting HTML to JSX

We will replace all the existing HTML code (starting with the <head> tag and ending with the <body> code with the HTML coming from the static HTML template, but we must also modify it to make it compliant with the JSX syntax.

We will now have to adapt the static HTML code to the JSX syntax. To do that we must perform the following steps:

  1. Go to the following website: HTML to JSX Converter | DivMagic
  2. Copy and paste the contents of the $HTML_TEMPLATE/index.html file into the left pane (named Input (HTML) - Paste your HTML here)
  3. The converted JSX output will be displayed on the right.
  4. Click on “Copy to Clipboard” and paste the contents of the file in the $NPM_TEMPLATE/src/server/templates/page/PageHome.jsx between the <> and </> tags, replacing the <head> and <body> tags as well as their contents. Do NOT include the opening <html> and </html> tags.

If all goes well, the beginning of the file should look like this:

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

export const PageHome = () => {
    return (<>
  <head>
    <meta charSet="utf-8" />
    <meta
      content="IE=edge"
      httpEquiv="X-UA-Compatible"
    />
    <meta
      content="width=device-width, initial-scale=1"
      name="viewport"
    />
    <title>
      Solid Template
    </title>
    <link
      href="https://fonts.googleapis.com/css?family=IBM+Plex+Sans:400,600"
      rel="stylesheet"
    />
    <link
      href="dist/css/style.css"
      rel="stylesheet"
    />
    <script src="https://unpkg.com/animejs@3.0.1/lib/anime.min.js" />
    <script src="https://unpkg.com/scrollreveal@4.0.0/dist/scrollreveal.min.js" />
  </head>
  <body className="is-boxed has-animations">    

Register the page

The last step before deploying our template is now to register the page in Jahia. To do so, at the bottom of the PageHome.jsx file, a jahiaComponent declaration has already been generated and looks like this:

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)
}    

The above code registers our component as a template using the file PageHome.jsx. It will be used to render content objects of type jnt:page. You can keep it as it is, no need to modify the registration.

That’s it, we are ready to build and test our project.

Initial build and test

We will now build the project and deploy it to see the current progress.

First launch the install of the dependencies using:

Linux/macOS:

cd $NPM_TEMPLATE
yarn

Windows:
cd $env:NPM_TEMPLATE
yarn    

This will download all the dependencies for the project.

Once that is complete, simply launch:

yarn watch    

The above command starts our project in “watch” mode, which means that any changes we do to project files will automatically trigger a repackaging and redeployment on the server, making it easy and fast to test changes.

Note : After a deploy with the watch mode, a sleep time is configured to avoid triggering too much module import on the backend, you can adjust it in the webpack.config.js file.

Ensure you watch the Docker logs to check if the deployment has finished before reloading. Check the logs (using docker logs -f jahia-npm-alpha-dev) on the Docker container, you should see something like this, indicating successful deployment:

2023-11-22 10:42:26,726: INFO  [Activator] - --- Finished starting DX OSGi bundle solid-template v1.0.0 [175] in 2ms --    

Connect to Jahia by opening a browser at URL http://localhost:8080 and login in with the default credentials root/root1234.

Then navigate to Administration -> Modules and Extensions -> Modules and in the search type “solid” to check if the JavaScript module is present and activated. It should look like this:

We should now be able to use our template set, we’ll now use a command to create a site using that template set. To do so open another terminal (as the current one is still running the yarn watch command) and execute this curl request:

curl --request POST \
  --url http://localhost:8080/modules/api/provisioning \
  -u 'root:root1234' \
  --header 'Content-Type: application/yaml' \
  --data '- createSite:
  siteKey: "solid"
  title: "Solid Project"
  templateSet: "solid-template"
  locale: "en"'    

If you’re curious about this API, you can find its documentation here: https://academy.jahia.com/documentation/jahia/jahia-8/dev-ops/provisioning/about-provisioning#api

Once the project is created, in the main Dashboard you will see the new solid project.

Simply click on it to open the page composer UI. You should see something like this:

As you can see, it doesn’t (yet) look like our template, because we have to add the stylesheet and the images in the proper locations to get everything to look right.

CSS Installation

To do so, we must add some imports to get the context. You need to modify the $NPM_TEMPLATE/src/server/templates/page/PageHome.jsx file to add an import for the AddResources component :

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

export const PageHome = () => {
    return (<>
	//HTML code
    );
}
//Properties    

To install the CSS you will need to replace the line:

    <link rel="stylesheet" href="dist/css/style.css"></link>    

With:

<AddResources type='css' resources='style.css'/>    

The AddResources component will make sure that the CSS is properly positioned in the HTML head tag even if included anywhere in the page. This makes it possible to use it in any component without worrying about its location.

Once you make this change you should be able to reload the page and the CSS should be applied as illustrated below:

 

Then we need to change the path for images, as we can see in the above illustration that they don’t have valid URLs. We will first use a const that will contain the path to our module the following way:

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

export const PageHome = () => {
    const {renderContext, currentResource} = useServerContext();
    const modulePath = renderContext.getURLGenerator().getCurrentModule();
    return (<>
	//HTML code
    );
}    

The above code retrieves the renderContext object from the rendering system, which contains information about the current context and access to various helper methods. Among them is the URLGenerator, which will help us retrieve and generate URLs relative to the current component. The getCurrentModule() call on the URLGenerator gives us a URL for the path of our JavaScript module.

So the first img tag src becomes:

src={buildUrl({ value: modulePath + '/images/logo.svg'}, renderContext, currentResource)}    

We should now do the same for all images. You could for example use a regular expression such as the following:

src=".*/images/(.*)"    


And do the replacement using:

src={buildUrl({ value: modulePath + '/images/$1'}, renderContext, currentResource)}    

There is a script at the end of the page that looks like this:

<script src="dist/js/main.min.js" />    

We will replace it with:

<AddResources type={'javascript'} resources='main.min.js' targetTag='body' />
    

The targetTag parameter tells the component that the script should be added at the end of the <body> tag content instead of the end of the <head> tag content.

All the <script> tags that have absolute URLs (starting with http) should not be modified and left as-is.
You can now reload the page it should look something like this:

Page template update

We will now modify our initial page template to make it possible to insert new content. In order to do this we will add an Area component that makes it possible to add an area in the page where content may be added.

You need to import the Area component at the top of $NPM_TEMPLATE/src/server/templates/page/PageHome.jsx file.

Our second line then becomes:

import {useServerContext, AddResources, buildUrl, Area} from '@jahia/js-server-core';
    
Now we need to call this component inside our page to add a new area named pagecontent.

Basically, the new content for the <main> tag of the src/server/templates/page/PageHome.jsx file should look like this:

        <main>
            <Area name={'pagecontent'}/>
            ... static HTML sections ...
        </main>

This helper will insert a blank area where we will be able to add our new content items. You will now see a Add content button in the page which you can use to create content of any type directly in the page.

Test our updates

Since we are using the “watch” system, simply reloading the Jahia Page Composer browser window will be sufficient to load all the changes.

Note the Add content button just above the hero section.

That’s it!

Congratulations, you now have static HTML deployed from your Jahia JavaScript module and made it possible to insert new content in it!

Next step

Continue to creating your first Jahia component