Migrate an existing design to the new build

This chapter provides a short migration guide to the conversion of an existing design for CX version 1.3 or lower to the new design build. For basic information on the new design build, please consider the corresponding Wiki page on GitHub.

As a first step of the migration, it is required to set up the project structure. It’s recommended that you start with the Scaffold Design instead of creating the structure all by yourself. Also consider reading this chapter before you start with the migration.

Content Elements

Now you can start the migration by transforming the content elements. This step will be explained on an example:

Content element from the old design creator build.
<div class="content-element image-wrapper" data-bsi-element="image">
    <div class="row">
        <div class="flex">
            <div class="element">
                <div class="image">
                    <img data-bsi-element-part="image" src="{{ src ?: baseUrl|raw ~ "/img/placeholder.jpg" }}" alt="" />
                </div>
                <div class="image-legend" data-bsi-element-part="plain-text">{{ legend ?: "Lorem ipsum image description" }}</div>
            </div>
        </div>
    </div>
</div>
Corresponding entry in the design.properties file.
element.image.label=Image
element.image.description=with description
element.image.icon=image
element.image.parts.image.label=Image
element.image.parts.plain-text.label=Description

The content elements are usually organized in Twig files inside a content-elements folder. While the corresponding properties are placed in a single design.properties file. In the new build process, it’s recommended to keep it all together in a single folder and separated from any other content element. So take a look on the existing content elements from the scaffold design. They are all nicely organized in separate folders. So create a new folder for your own element:

Folder structure of a single content element.
.
└───image
        index.js (1)
        placeholder.jpg (2)
        template.twig (3)
        styles.less (4)
1 This file will contain the content element specification.
2 Feel free to place any content element related assets here.
3 The Twig template for our content element.
4 Any content element related Stylesheets. This can also be a LESS or SASS file.

Create the index.js and template.twig files inside this folder and feel free to add any related assets too. In our example, we add the placeholder.jpg here. Now we can create the template.twig:

The transformed template for the content element.
<div class="content-element image-wrapper" data-bsi-element="image">
    <div class="row">
        <div class="flex">
            <div class="element">
                <div class="image">
                    <img data-bsi-element-part="image" src="{{ url ?: bsi_cx_asset('./placeholder.jpg') }}" alt="" />
                </div>
                <div class="image-legend" data-bsi-element-part="plain-text">{{ legend ?: "Lorem ipsum image description" }}</div>
            </div>
        </div>
    </div>
</div>
The content element specification in the index.js file.
require('./styles.less'); (1)

const {cx, Icon} = require('@bsi-cx/design-build'); (2)

module.exports = cx.contentElement
  .withElementId('image')
  .withLabel('Image')
  .withDescription('with description')
  .withIcon(Icon.IMAGE)
  .withFile(require('./template.twig'))
  .withParts(
    cx.part.image
      .withLabel('Image'),
    cx.part.plainText
      .withLabel('Description'));
1 Include any related stylesheets right at the beginning of your content element specification.
2 Be sure you use require() instead of import.
Be aware, that there are some advanced features available with the new design build. For example referenced content element parts, which can be useful in complex content elements.

Once you have finished creating your content element, you can include them in your design specification. The design specification is contained in the design.js file and replaces the design.properties. You find the design.js at the root folder of your template.

The design specification for the transformed design.
require('./styles/styles.scss'); (1)

const {cx, Design} = require('@bsi-cx/design-build');

/**
 * @type {Design}
 */
module.exports = cx.design
  .withTitle('BSI - Landingpage') (2)
  .withAuthor('BSI Business Systems Integration AG') (3)
  .withDate('14.04.2022')
  .withContentElementGroups(
    cx.contentElementGroup
      .withGroupId('content')
      .withLabel('Content')
      .withContentElements(
        require('./content-elements/content/image'), (4)
        require('./content-elements/content/text')));
1 You can also include global stylesheets (CSS, LESS or SASS) here.
2 Title of this template, corresponds to the template.name from the design.properties file.
3 The author of this template, corresponds to the template.author from the design.properties file.
4 This is our transformed content element. The path points to the folder. Since it contains an index.js, it’s not required to mention the filename here.

Styles

If your content element uses any [styles], you must transform them to a Java Script styles definition:

The style definition in the old design.properties format.
style.element-width.label=Element width
style.element-width.class.element-with-unset.label=None
style.element-width.class.element-width-full.label=Full
style.element-width.class.element-width-left-right.label=Label left, field right

The transformation to the new format is pretty straightforward:

The style definition in the new Java Script format.
const {cx} = require('@bsi-cx/design-build');

module.exports = cx.style
  .withIdentifier('element-width')
  .withLabel('Element width')
  .withCssClasses(
    cx.cssClass
      .withLabel('None')
      .withCssClass('element-with-unset'),
    cx.cssClass
      .withLabel('Full')
      .withCssClass('element-width-full'),
    cx.cssClass
      .withLabel('Label left, field right')
      .withCssClass('element-width-left-right'));

It’s recommended to place the style definition in a separate Java Script file. If your style is exclusively for one element, you can place the file right next to the element definition. Otherwise, you should put it in the configs/styles folder inside your template root. To use a style in your content element, simply reference the file:

Use a style definition in your content element.
const {cx, Icon} = require('@bsi-cx/design-build');

module.exports = cx.contentElement
  .withElementId('image')
  .withLabel('Image')
  .withDescription('with description')
  .withIcon(Icon.IMAGE)
  .withFile(require('./template.twig'))
  .withStyleConfigs(require('../../../configs/styles/fade-out')) (1)
  .withParts(
    cx.part.image
      .withLabel('Image'),
    cx.part.plainText
      .withLabel('Description'));
1 Just pass the style definition to the builder using withStyleConfigs() and require().

Design and Preview Templates

To bundle your design and preview templates, create a new preview.twig and design.twig file inside the template root folder. To prevent code duplication, it’s recommended to create a _layout.twig template and extend it in your design.twig and preview.twig. Take a look at the following example:

The contents of a simple _layout.twig template.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <title>{{ properties.title }}</title>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <link rel="stylesheet" href="{{ bsi_cx_css_href() }}"/> (1)
</head>
<body class="d-flex flex-column min-vh-100">
{% apply spaceless %}
    <header id="header" data-bsi-dropzone="header">
        {% block header %}{% endblock %}
    </header>
    <main id="content" data-bsi-dropzone="content">
        {% block content %}{% endblock %}
    </main>
    <footer id="footer" data-bsi-dropzone="footer">
        {% block footer %}{% endblock %}
    </footer>
{% endapply %}
    <script src="{{ bsi_cx_js_module_runtime_href() }}" data-bsi-remove-if="draft" defer="defer"></script> (2)
    <script src="{{ bsi_cx_js_module_href('main') }}" data-bsi-remove-if="draft" defer="defer"></script> (3)
    {{ bsi_cx_js_module_missing_chunks_import() }} (4)
</body>
</html>
1 Use the bsi_cx_css_href() Twig helper to include your stylesheets. More options can be found here.
2 You can skip this line if you don’t have any Java Script modules configured.
3 Use the bsi_cx_js_module_href() Twig helper to include a Java Script module. You can skip this line if you don’t have any Java Script modules configured.
4 This imports all missing chunks, related to Java Script modules. You can skip this line if you don’t have any Java Script modules configured. More information on including Java Script in your design can be found here.

Now you can extend the blocks from the _layout.twig in your design.twig and preview.twig. The following example illustrates this step for the design.twig:

The design.twig extends the _layout.twig.
{% extends '_layout.twig' %}

{% block header %}
    {% include './content-elements/header/banner/template.twig' %}
{% endblock %}

{% block content %}
    {% include './content-elements/content/title-h1/template.twig' %}
    {% include './content-elements/content/text/template.twig' %}
{% endblock %}

{% block footer %}
    {% include './content-elements/footer/two-col/template.twig' %}
{% endblock %}

Java Script

You have two options to include your Java Script code:

  1. Place them in the static folder inside your templates root and include them with bsi_cx_asset().

  2. Create a module in the modules folder and take full advantage of all modern Java Script.

Stylesheets

Your global can place your global stylesheets directly in the styles folder, located at your template root. You can also place any content element specific styles here instead of moving them to the specific content element’s own folder. To bundle your stylesheets, you must reference them in your design.js:

Including a stylesheet in your design.
require('./styles/styles.scss');

Properties

The new design build uses Java Script files instead of YAML. The properties.js file is a CommonJS module, that exports a simple Java Script object {}. Feel free to organize your properties as you wish. To access the properties inside your stylesheets and templates, you can use the bsiProperty() helper. Take a look at the following example:

Old YAML properties file.
styles:
    primary-color: '#ed4546'
    secondary-color: '#efefef'
New Java Script properties file.
const {css} = require('@bsi-cx/design-build');

module.exports = {
  styles: {
    'primary-color': css.color('#ed4546'),
    'secondary-color': css.color('#efefef')
  }
};
Use the css helper to get the most out your properties. More information on this feature can be found here.
Access the properties inside your Twig templates.
{% set color = properties.styles['primary-color'] ?: '#ff00ff' %}
Use the bsiProperty() helper inside your templates.
@color: bsiProperty('styles.primary-color');

Build Configuration

In order to compile, it’s required to add your template to the build configuration in the webpack.config.js file at the project root folder.

Content of the webpack.config.js build configuration file.
const path = require('path');

const {BuildConfig, ModuleConfig, WebpackConfigBuilder, Version, DesignType} = require('@bsi-cx/design-build');

module.exports = WebpackConfigBuilder.fromConfigs(
  new BuildConfig()
    .withName('landingpage') (1)
    .withVersion('1.0.1-alpha') (2)
    .withTargetVersion(Version.CX_1_3) (3)
    .withDesignType(DesignType.LANDINGPAGE) (4)
    .withRootPath(path.resolve(dirname, 'templates', 'landingpage')) (5)
    .withPropertiesFilePath(path.resolve(dirname, 'properties.js')) (6)
    .withModules(
      new ModuleConfig() (7)
        .withPath('main.js')
        .withName('main')));
1 The name of this template.
2 The current version of this template, optional but recommended.
3 The target BSI CX version. The build is capable of converting a design to the required format of various CX versions.
4 What type of design is your template?
5 The path to your template root folder. This is where your design.js is located.
6 The path to your properties.js file.
7 Configure your Java Script modules here.