Vous consultez actuellement l'aide de la version:

Les applications d’une seule page (SPA) peuvent améliorer considérablement l’expérience des utilisateurs de sites web. Le souhait des développeurs est de pouvoir créer des sites avec des structures SPA. Les auteurs, pour leur part, souhaitent modifier facilement du contenu dans AEM pour un site conçu à l’aide de telles structures.

La fonction de création d’application d’une seule page constitue une solution complète pour la prise en charge de ce type d’application dans AEM. Cet article présente un exemple d’application d’une seule page (SPA), explique comment elle est structurée et vous permet de rapidement prendre en main votre propre application d’une seule page.

Attention :

La fonction d’éditeur d’application d’une seule page (SPA) a été introduite dans AEM 6.4 et constitue actuellement un aperçu technologique. L’éditeur de SPA sera livré séparément du Quickstart AEM dans un Service Pack à venir pour AEM 6.3 et 6.4.

  • Cette fonction est en cours développement, et la documentation est sujette à modification.
  • L’éditeur de SPA est la solution recommandée pour les projets nécessitant un rendu côté client basé sur la structure SPA (par exemple, React).

Introduction

Cet article résume le fonctionnement de base d’une application d’une seule page simple et ce que vous devez savoir pour que la vôtre soit opérationnelle.

Pour plus de détails sur le fonctionnement des applications d’une seule page dans AEM, consultez les documents suivants :

Remarque :

Pour pouvoir créer du contenu dans une application d’une seule page, il doit être stocké dans AEM et exposé par le modèle de contenu.

Une SPA développée en dehors d’AEM n’est pas modifiable si elle ne respecte pas le contrat de modèle de contenu.

Ce document décrit la structure d’un exemple d’application d’une seula page (SPA) et explique son fonctionnement pour que vous puissiez appliquer cette information à votre propre projet.

Dépendances, configuration et construction

En plus de la dépendance React attendue, l’exemple d’application d’une seule page tire parti de bibliothèques supplémentaires pour optimiser la création de l’application d’une seule page.

Dépendances

Le fichier module.json définit les exigences du module d’application d’une seule page global et est répertorié ici.

{
  "name": "react-app",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "start": "react-scripts start",
    "build": "webpack && clientlib --verbose"
  },
  "proxy": {
    "/content": {
      "target": "http://localhost:4502"
    }
  },
   "dependencies": {
    "@adobe/cq-react-editable-components": "^0.0.28",
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "react-open-weather": "^0.3.0",
    "react-router-dom": "^4.2.2"
  },
}

Puisque cet exemple est basé sur le framework React, il existe deux dépendances spécifiques à React qui sont obligatoires dans le fichier module.json :

"react": "^16.2.0",    
"react-dom": "^16.2.0",

De plus, aem-clientlib-generator est utilisé pour automatiser la création de bibliothèques clientes dans le cadre du processus de construction.

"aem-clientlib-generator": "^1.4.1",

Bien que cela ne soit pas obligatoire, il est recommandé de simplifier la création de votre application. Plus de détails à ce sujet sont disponibles sur GitHub ici.

aem-clientlib-generator est configuré dans le fichier clientlib.config.jscomme suit.

module.exports = {
    // default working directory (can be changed per 'cwd' in every asset option)
    context: __dirname,

    // path to the clientlib root folder (output)
    clientLibRoot: "./../content/jcr_root/apps/we-retail-journal/react/clientlibs",

    libs: {
        name: "we-retail-journal-react",
        allowProxy: true,
        categories: ["we-retail-journal-react"],
        serializationFormat: "xml",
        assets: {
            js: [
                "dist/**/*.js"
            ],
            css: [
                "dist/**/*.css"
            ]
        }
    }
};

Construction

En réalité, la construction de l’application utilise Webpack pour la transpilation, en plus du aem-clientlib-generator pour la création automatique de la bibliothèque cliente. Par conséquent, la commande de construction est similaire à :

"build": "webpack && clientlib --verbose"

Une fois construit, le module peut être téléchargé dans une instance AEM.

Exemple de structure d’application

Si vous ajoutez les dépendances et que vous construisez l’application d’une seule page selon notre exemple, vous disposez d’un module d’application d’une seule page opérationnel que vous pouvez télécharger dans votre instance AEM.

La section suivante de ce document explique comment l’application d’une seule page est structurée et décrit les fichiers importants qui pilotent l’application et leur interfonctionnement.

Le composant image est utilisé à titre d’exemple, mais tous les composants de l’application reposent sur le même concept.

index.js

Le point d’entrée dans l’application d’une seule page est bien entendu le fichier index.js présenté ici de manière simplifiée pour que l’on se concentre sur le contenu important.

import ReactDOM from 'react-dom';
import App from './App';

...

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

...

La principale finalité de index.js est de tirer parti de la fonction ReactDOM.render pour déterminer où, dans le DOM, injecter l’application.

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

Ceci est une utilisation standard de cette fonction, non spécifique à cet exemple d’application.

App.js

En effectuant le rendu de l’application, index.js appelle App.js, présenté ici dans une version simplifiée pour que l’on se concentre sur le contenu important.

import React, {Component} from 'react';
import Page from './components/Page';

...

class App extends Component {

    render() {
        return <Page/>
    }
}

export default App;

App.js sert principalement à encapsuler les composants racine qui forment l’application.

Page.js

En effectuant le rendu de la page, App.js appelle Page.js répertorié ici.

import React from 'react';
import { Container, withModel } from '@cq/cq-react-editable-components';

class Page extends Container {

    render() {
        let classNames = this.props.cq_model && this.props.cq_model.cssClassNames;

        return <div className={classNames}>{this.innerContent}</div>;
    }
}

export default withModel(Page);

La classe Page étend Container contenant les méthodes de contenu interne qui peuvent ensuite être utilisées.

Container accède à la représentation JSON du modèle de page et traite le contenu pour encapsuler/décorer chaque élément de la page. De plus amples détails sur Container sont disponibles dans le document Plan directeur de SPA.

let classNames = this.props.cq_model && this.props.cq_model.cssClassNames;

L’objet props est fourni par le framework React et est disponible dans tous les composants, représentant l’API de ce composant.

L’objet cq_model est le résultat de l’encapsulation de l’élément et contient le modèle du composant actif.

Pour plus d’informations sur la fonction withModel, reportez-vous à la section Exemples de cas d’utilisation de ce document.

Image.js

Avec la page rendue, les composants tels que Image.js présentés ici peuvent être rendus.

import React, {Component} from 'react';
import { MapTo } from '@cq/cq-react-editable-components';

require('./Image.css');

/**
 * Default Edit configuration for the Image component that interact with the Core Image component and sub-types
 *
 * @type EditConfig
 */
const ImageEditConfig = {

    dragDropName: 'image',

    emptyLabel: 'Image',

    isEmpty: function() {
        return !this.props || !this.props.cq_model || !this.props.cq_model.src || this.props.cq_model.src.trim().length < 1;
    }
};

/**
 * Expected usage of the Image Component.
 *
 * <Image
 *      cq_model='the whole Object holding information for the image from the model.json response' />
 *
 * Please see the package.json for the proxy settings.
 */
class Image extends Component {

    hasLink() {
        return this.props && this.props.cq_model && this.props.cq_model.link;
    }

    get content() {
        let alt;
        let displayPopupTitle;
        let src;
        let title;
        let id;

        if (this.props.cq_model) {
            alt = this.props.cq_model.alt;
            displayPopupTitle = this.props.cq_model.displayPopupTitle; // TODO: it is missing in the JSON
            src = this.props.cq_model.src;
            title = this.props.cq_model.title;
            id = this.props.cq_model.path.substr(this.props.cq_model.path.lastIndexOf('/')+1);
        }

        return <img id={id} src={src} alt={alt} title={displayPopupTitle && title}/>
    }

    get linkedContent() {
        let alt;
        let fileReference;
        let link;
        let title;

        if (this.props.cq_model) {
            alt = this.props.cq_model.alt;
            fileReference = this.props.cq_model.fileReference; // TODO: it is missing in the JSON
            link = this.props.cq_model.link;
            title = this.props.cq_model.title;
        }

        return <a href={link} data-title={title || alt} data-asset={fileReference}>
                {this.content}
            </a>
    }

    render() {
        let innerContent;

        if (this.hasLink()) {
            innerContent = this.linkedContent;
        } else {
            innerContent = this.content
        }

        return (<div className="cmp-image">
                {innerContent}
            </div>);
    }
}

MapTo('weretail/components/content/image')(Image, ImageEditConfig);

Les applications d’une seule page dans AEM ont comme principale finalité de mapper les composants SPA aux composants AEM et de mettre à jour le composant lorsque le contenu est modifié (et vice versa). Consultez le document Introduction à la création d’une application d’une seule page qui présente ce modèle de communication.

MapTo(’weretail/components/content/image’)(Image, ImageEditConfig);

La méthode MapTo mappe le composant SPA au composant AEM. Elle prend en charge l’utilisation d’une seule chaîne ou d’une table de chaînes.

ImageEditConfig est un objet de configuration qui contribue à activer les fonctionnalités de création d’un composant en fournissant les métadonnées nécessaires à l’éditeur pour générer des espaces réservés.

S’il n’y a pas de contenu, des libellés sont fournis sous forme d’espaces réservés pour représenter le contenu vide.

Exemples de cas d’utilisation

Rendu des parties de la page (références statiques)

Si vous transmettez la propriété path, vous pouvez afficher certaines parties de la page. Cela est nécessaire si les enfants du modèle de la page doivent être ciblés, par exemple lorsque le contenu que vous souhaitez créer réside entre d’autres contenus.

Votre index.js sera similaire à ceci :

import ReactDOM from 'react-dom';
import App from './App';
import { PageModelManager } from '@cq/cq-react-editable-components';

...

PageModelManager.init().then(function() {
    ReactDOM.render(<App/>, document.getElementById('page'));
});
...

Votre App.js sera similaire à ceci :

import React, {Component} from 'react';
import Page from './components/Page';
import Text from './components/Text';

...

class App extends Component {

    render() {
        return <Page cq_model_path="path/to/page1"/>
            <Text cq_model_path="path/to/text1"/>
    }
}

export default App;

Exportation d’un composant modifiable

Vous pouvez exporter un composant et le laisser modifiable.

import React, { Component } from 'react';
import { MapTo } from '@cq/cq-react-editable-components';

...

const EditConfig = {...}

class PageClass extends Component {...};

...

export default MapTo('we-retail-journal/react/components/structure/page')(PageClass, EditConfig);

La fonction MapTo renvoie un composant qui est le résultat d’une composition qui étend la PageClass fournie avec les noms de classe et les attributs qui permettent la création. Ce composant peut être exporté pour être instancié ultérieurement dans le balisage de votre application.

Lorsqu’il est exporté à l’aide des fonctions MapTo ou withModel, le composant Page est encapsulé avec un composant ModelProvider qui fournit aux composants standard un accès à la dernière version du modèle de page ou à un emplacement précis dans ce modèle de page.

Pour plus d’informations, voir le document Plan directeur de SPA.

Remarque :

Par défaut, vous recevez le modèle complet du composant lorsque vous utilisez la fonction withModel.

Ce produit est distribué sous licence Creative Commons Attribution - Pas d’utilisation commerciale - Partage à l’identique 3.0 non transposé  Les publications Twitter™ et Facebook ne sont pas couvertes par les dispositions Creative Commons.

Mentions légales   |   Politique de confidentialité en ligne