0.3.11 • Published 5 years ago

@cqfactory/component-generator v0.3.11

Weekly downloads
2
License
GPL-3.0-or-later
Repository
-
Last release
5 years ago

CQ-Factory Banner

Component-Generator for Adobe Experience Manager

Intro

The Component-Generator is a tool for creating Adobe Experience Manager components with support for the UI rendering technologies HTL/Sightly, ReactJS, Vue and Angular (current version supports only HTL and ReactJS). The user creates for each component a specific component-configuration file written in TypeScript, which the Component-Generator Builder uses to create components with Touch UI dialogues and support for the selected UI rendering technology.

Using React, it uses our fantastic React-Loader for AEM to render the React component into a basic HTL-file and it also provides the CQ-dialog properties for the React component .tsx file. All done without deploying special Java Sling Models (can be done to implement special Getters for properties) or AEM configurations. Works with AEM 6.4 SP2 or higher. For lower AEM versions we could provide special Sling Models.

The Component-Generator can easily integrated into existing AEM projects and helps you to create faster AEM components.

Benefits

We assume that your team does not need so much AEM developers anymore, because they can be replaced with (mostly cheaper and more available) real frontend developers. Using our experience through many AEM projects, we predict that you can save money and time in your AEM project, when moving away from the paradigm that you need a complete team of fullstack AEM developer to create components & templates. These guys can now concentrate on AEM backend stuff while your frontend belongings are now handled by a real frontend team (which could be easily outsourced). CQ-Factory Team Size

Fullsize view

Installing

For the latest stable version:

npm install -g @cqfactory/component-generator

Include as a dependency into existing package.json:

"devDependencies": {
    "@cqfactory/component-generator": "^0.3.11"

Usage

Include as a task into existing package.json

"scripts": {
    "build:components": "node node_modules/@cqfactory/component-generator/builder.js"

You can also add a specific folder. For default it would search the whole project.

"scripts": {
    "build:components": "node node_modules/@cqfactory/component-generator/builder.js --src ./myspecificfolder"

Example integration into a Webpack project.

{
  "name": "npm-component-generator",
  "version": "0.1.0",
  "description": "npm project for the component-generator",
  "main": "index.js",
  "dependencies": {
    "@types/react": "^16.8.17",
    "@types/react-dom": "^16.8.4",
    "jspath": "^0.4.0",
    "npm": "^6.9.0",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-fast-compare": "^2.0.4",
    "react-router": "^5.0.0",
    "react-router-dom": "^5.0.0",
    "react-scripts": "^2.1.8",
    "react-scripts-ts": "3.1.0",
    "react-styleguidist": "^9.0.6"
  },
  "devDependencies": {
    "@cqfactory/component-generator": "^0.3.1",
    "aem-clientlib-generator": "^1.4.1",
    "ajv": "^6.10.0",
    "awesome-typescript-loader": "^5.2.1",
    "babel-core": "^6.26.3",
    "babel-loader": "^8.0.5",
    "babel-preset-env": "^1.7.0",
    "babel-preset-react": "^6.24.1",
    "clone": "^2.1.2",
    "css-loader": "^2.1.1",
    "html-webpack-plugin": "^3.2.0",
    "node-sass": "^4.12.0",
    "sass-loader": "^7.1.0",
    "source-map-loader": "^0.2.4",
    "style-loader": "^0.23.1",
    "typescript": "^3.4.5",
    "webpack": "^4.31.0",
    "webpack-cli": "^3.3.1"
  },
  "scripts": {
    "build:components": "node node_modules/@cqfactory/component-generator/builder.js",
    "clean:dep": "rm -rf node_modules/",
    "clean:cqfactory": "rm -rf node_modules/@cqfactory",
    "webpack:prod": "webpack --mode production && clientlib --verbose"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "author": "CQ-Factory GmbH",
  "license": "GNU General Public License v3.0"
}

Sample React Component

Imagine your pure ReactJS developer has created an amazing stand-alone React component like this teaser. CQ-Factory Banner

All the developer has done was creating an index.tsx where the input fields for the CQ-dialog where pre-defined and the component initialized:

import * as React from 'react';
import * as ReactDOM from 'react-dom';

import CqfTeaserReactComponent from './CqfTeaserReactComponent';
import './index.css';

export interface CqfTeaserReactComponentProps {
  cqComponent?: any;
}

// Pre-defined properties for the CQ-dialog.
export interface DialogProperties {
  teaserHeadline?: string;
  teaserText?: string;
  imageFileReference?: string;
}

// Using some test values.
const teaserProps: DialogProperties = {
  teaserHeadline: 'This is the teaser headline',
  teaserText: "Sample text",
  imageFileReference: "CQF-Mountains1.jpg"
};

ReactDOM.render(
  <CqfTeaserReactComponent cqComponent={teaserProps}/>,
  document.getElementById('cqf-teaser-react-app') as HTMLElement
);

This is the React component:

import * as React from 'react';
import './CqfTeaserReactComponent.scss';
import {CqfTeaserReactComponentProps} from "./index";

// Use an external library which provides atomic elements.
import Headline from '@cqfactory/react-elements/components/Headline/Headline';

export default class CqfTeaserReactComponent extends React.Component<CqfTeaserReactComponentProps> {

  get teaserHeadline() {
    let teaserHeadline = this.props.cqComponent.teaserHeadline;
    return teaserHeadline ? teaserHeadline :
      <p className="cqf-teaser-warning">Teaser Headline is empty, please configure it in the CQ-dialog!</p>;
  }

  get teaserTextContent() {
    let teaserTextContent = this.props.cqComponent.teaserText;
    return teaserTextContent ? <div dangerouslySetInnerHTML={{__html: teaserTextContent}}/> :
      <p className="cqf-teaser-warning">Teaser text is empty, please configure it in the CQ-dialog!</p>;
  }

  render() {
    return (<div className="CqfTeaserReactComponent">
      <div className="teaserboxlarge section">
        <div className="teaserBox">
          <Headline headline="This is my atomic-headline from @cqfactory/react-elements" topic="" />
          <div className="image">
            <img src={this.props.cqComponent.imageFileReference}
                 className="full-width">
            </img>
          </div>
          <div className="text">
            <h3>{this.teaserHeadline}</h3>
            <p>{this.teaserTextContent}</p>
          </div>
        </div>
      </div>
    </div>);
  }
}

Now, this great React application should be included into an AEM project. The pure React developer does not know anything about AEM and this is ok! So this developer only has to create a component-configuration file, based on TypeScript and the CQ-Factory Component-Generator classes, to ensure correct value usage. This example component-configuration file would now create a React enabled AEM component with a Touch UI dialog and the needed TSX files.

File: /aemproject/npm/src/cqfactory-teaser-react.component.ts

import {
    AEMTouchUIDialog,
    TouchUIDialogTab,
    TouchUIField,
    ComponentGenerator
} from '@cqfactory/component-generator';
import { ReactConfiguration } from '@cqfactory/component-generator/uiconfigs/reactConfiguration';

/* Definition of dialog tabs. */
const tabs: TouchUIDialogTab[] = [
    /* Headline und Text tab. */
    {
        title: 'Headline und Text',
        fields: [
            {
                label: 'Headline',
                type: TouchUIField.Text,
                databaseName: 'teaserHeadline',
                description: 'Teaser Headline.'
            },
            {
                label: 'Text',
                type: TouchUIField.RichText,
                databaseName: 'teaserText',
                description: 'Teaser Text.'
            }
        ]
    },
    /* Image tab. */
    {
        title: 'Image Tab',
        fields: [
            {
                label: 'Teaser Image',
                type: TouchUIField.Imagefield,
                databaseName: 'image',
                description: 'Teaser Image.',
                isRequired: false
            },
            {
                label: 'Teaser Image Alternative Text',
                type: TouchUIField.Text,
                databaseName: 'image/alt',
                description: 'Textual alternative of the meaning or function of the image, for visually impaired readers.'
            },
            {
                label: 'Image is decorative',
                type: TouchUIField.Checkbox,
                databaseName: 'image/isDecorative',
                uncheckedValue: 'false',
                value: '{Boolean}true',
                checked:
                    '${not empty cqDesign.isDecorative ? cqDesign.isDecorative : false}',
                description: 'Check if the image should be ignored by assistive technology and therefore does not require an alternative text. This applies to decorative images only.'
            },
            {
                label: 'Mein Hidden Field',
                type: TouchUIField.HiddenField,
                databaseName: 'image/sling:resourceType',
                value: 'componentgenerator/components/content/image'
            }
        ]
    }
];

export const exampleTouchUIDialog: AEMTouchUIDialog = {
    buildComponent: true /* Create the component from scratch */,
    buildConfigForAem: true /* Create the file .content.xml */,
    overwriteAllFilesOnBuild: true /* Works only when buildComponent: true, later deactivate it to avoid recreation. */,
    componentName: 'CQ-Factory Teaser React',
    componentGroup: 'componentgenerator',
    componentDescription: 'CQ-Factory Teaser React Component',
    noDecoration: false,
    isContainer: false,
    componentPath: './../ui.apps/src/main/content/jcr_root/apps/componentgenerator/components/content/cqfteaserreact',
    title: 'CQ-Factory Teaser React Component',
    tag: 'div',
    css: 'cqf-teaser-react',
    tabs,
    analytics: {
        values: ['value1', 'value2'],
        events: ['event1', 'event2']
    },
    fullyQualifiedClassName:
        'de.cqfactory.componentgenerator.core.models.TeaserReactComponentModel', /* Only needed for manipulating JCR values */
    resourceSuperType: ''
};


let reactConfiguration = new ReactConfiguration(
    'cqf-teaser-react-app',
    'CqfTeaserReactComponent',
    './src/components/cqfteaserreactcomponent'
);

/**
 * Special configuration for React only. 
 */
new ComponentGenerator(
    exampleTouchUIDialog,
    reactConfiguration
).writeFilesToAEM();

Running node node_modules/@cqfactory/component-generator/builder.js would search for all files containing *.component.ts in their filename: TypeScript REPL

When this task ended successfully, there will be a complete new folder /aemproject/ui.apps/src/main/content/jcr_root/apps/componentgenerator/components/content/cqfteaserreact created with all files for this AEM-component. No changes are needed. Just leave it as it is (but you can!): TypeScript REPL

There is also a newly created React app folder /aemproject/npm/src/components/cqfteaserreactcomponent, containing the React component index.tsx with our provided magic AEM React-Loading mechanism: TypeScript REPL

The Component-Generator also created a basic react component (CqfTeaserReactComponent.tsx), which gives the developer access to all CQ-dialog properties via this.props.cqComponent: TypeScript REPL

After deploying this component to an AEM instance, it will work with its basic functionality: TypeScript REPL

Opening the CQ-dialog would show the JCR properties fields, which were previously defined in the file /aemproject/npm/src/cqfactory-teaser-react.component: TypeScript REPL

After saving the dialog, in this view it shows only what the JCR is containing - inside the React component: TypeScript REPL

This magic is done via our React-Loader which let React access the JCR properties (seen above in file CqfTeaserReactComponent.tsx): TypeScript REPL

Now that we have the basic component structure with a dialog, it is time to move the real React code inside the AEM project. All the developer has to do, is to copy & paste the content of the React component TSX-file into the created file CqfTeaserReactComponent.tsx: TypeScript REPL

Build with WebPack and deploy to AEM to see the result: TypeScript REPL

Modify a created component

After a component is created you want to change manually some stuff like the html, dialog and react files. To prevent overwriting of all files during next builder run, just switch in the component-configuration file the buildComponent parameter to false.

buildComponent: false 

Need Support?

The team of the CQ-Factory GmbH company (located in Munich/Germany) has years of experience in working with Adobe Experience Manager (formerly DAY/CQ5). We have supported many high level companies in Germany and worldwide. We would proudly support your project in integrating the Component-Generator to speed up your component development. You need also help in consulting, planning, architecture and developing an Adobe Experience Manager environment? Just ask us!

Visit: www.cq-factory.de

Email: info@cq-factory.de

0.3.11

5 years ago

0.3.10

5 years ago

0.3.9

5 years ago

0.3.8

5 years ago

0.3.7

5 years ago

0.3.6

5 years ago

0.3.5

5 years ago

0.3.4

5 years ago

0.3.3

5 years ago

0.3.2

5 years ago

0.3.1

5 years ago

0.3.0

5 years ago

0.2.2

5 years ago

0.2.1

5 years ago

0.2.0

5 years ago

0.1.0

5 years ago