@cqfactory/component-generator
v0.3.11
Published
Builds ReactJS/Vue/Angular enabled AEM Touch UI components with dialogue.
Downloads
11
Maintainers
Readme
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).
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.
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:
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!):
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:
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:
After deploying this component to an AEM instance, it will work with its basic functionality:
Opening the CQ-dialog would show the JCR properties fields, which were previously defined in the file /aemproject/npm/src/cqfactory-teaser-react.component:
After saving the dialog, in this view it shows only what the JCR is containing - inside the React component:
This magic is done via our React-Loader which let React access the JCR properties (seen above in file CqfTeaserReactComponent.tsx):
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:
Build with WebPack and deploy to AEM to see the result:
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: [email protected]