I felt it was about time I found a moment to write this article. I am sure that more than one frontend developer (especially in the role of tech lead or frontend architect) working in AEM projects, will find it useful. It's very important you understand that the advise I give here is my sole opinion and preferences, but it's backed up by 5 years of experience as Frontend Tech Lead in large enterprise platforms built on top of AEM.
Like every architecture topic, it is a bit dense, so I will split it into different subtopics, for it to be easier to follow.
Tech stack
I will presuppose that the whole project is structured following the Maven Archetype https://maven.apache.org/guides/introduction/introduction-to-archetypes.html (or the Adobe Archetype, in the best of cases), and obviously, that Maven is the compilation tool to put it together. Other assumptions, you're using at least version 6.3 of AEM, Maven 3.5+, Java8, and Sling Models. (Although the backend tech matters little, to be honest, the Maven version does not)
In the frontend, our stack will be ES6 (no frameworks for now, but we will integrate one at a later step -aka a new post- ), we will use Redux for state management, and obviously our html will be written as HTL templates. Ready to go?
Folder Structure
The first thing you need to consider, is your folder structure. And to decide your folder structure, you may need to work together with your backend tech leads or solution architect.
Usually they will have a strong opinion on the subject, and the (client) requirements will play a major role. Let's work on the hypothesis of having a large enterprise project between hands. That will imply perhaps, a lot of sub-projects under a common dependency. Each one of those, we will call 'tenants'.
So let's propose the following structure (I know it will look familiar to people working with AEM, so I won't go into details).
In our hypothetical project, the sling models are in our core package, the .html files (HTL files), the dialogues, etc, will be in our components package, together with the common frontend files used by all tenants (javascript vendor, abstracts and shared sass code), the frontend files (js and sass) files for each one of the tenants, will be in a their respective tenants/tenant-name package. Notice that tenants
is a module on its own.
Clientlibs
If you've been working with AEM for a while, as a frontend or backend developer, you're very likely familiar with AEM's pattern for frontend code, the client-side libraries (known by AEM devs as clientlibs). You can read more about them here -> https://helpx.adobe.com/experience-manager/6-4/sites/developing/using/clientlibs.html
Clientlibs are categorised, (precisely by declaring a category name for each one of them), and you can have as many categories as you wish (hold that thought!). AEM as a system downloads its own core clientlibs, (think granite for example, that makes all authoring interface dialogues work etc). This clientlib, has a dependency on jQuery, so you have jQuery available in the frontend if you need it, even if you don't introduce it yourself. (Of course, you're restricted to a particular version!).
Remember when I said you can have all the clientlibs you wish to have? Well, in theory, you can. In practice, you probably want to make that decision depending on the protocol that will be serving your site. If it's http/2, (and I encourage you to fight for that!) you may have a clientlib category per component or module. Conversely, if you're on HTTP 1.1, then you are probably better aggregating all your bundles into one, and serving them as a single category per 'wcmmode' (author or preview/publish). That's an important decision at the time of designing your frontend build. So you please make that question early to your DevOps team or architect. We will speak about aggregation and compression, in a later post.
Please notice that AEM supports compilation of LESS natively. But we won't use it. We will do our CSS pre processing on our own.
Components
In the latest versions of AEM, it is a good practice to classify components per content or structure, meaning whether they have a structural function or will be dragged and dropped into the content. I believe that's a great utility to understand what may be a common asset or component, and what serves a more dedicated, specific role.
With that in mind, let's look at what the structure inside of a tenant may look like:
Additionally, inside of each component folder, you would have a
- componentname.entry.scss
- componentname.entry.js
- componentname.config.js (optional when necessary)
Shared, abstract and vendor
Earlier in this post we mentioned these categories and explained that they're recommended to exist in a common dependency. By shared and abstract we mean for example utility code such as mixins, functions, maps, and global variables that serve for the purpose of making those work.
Since this code is consumed by all tenants, we will place it in the components package. Not only it makes 0 sense to repeat this code several times, it does not make sense to maintain it several times. It also does not belong in the tenants space, where only tenant specific code must be.
Now we have added all these, our structure looks something like the one below.
Frontend Build
Now we can finally get to the fun part. Installing and configuring our frontend build. I recommend this global frontend build to be in a separate module. If you want to know more about it (what technologies we will be using, how we will configure it to grab our entries, etc), read the next post, !
And while I write it, you can watch this video:
Top comments (25)
I am using spa template given by adobe. Currently stuck with integrating parsys in column control or layout grid component. Can you help ?
Hi Pavan, Nice to meet again, were you able to handle the nested component in SPA framework ? I've gone through your code. Were you able to handle this usecase, i would like to get more info about this. - Jithin
I would love to, but I am afraid I need a bit more information to be able to help...
I am following this template --> helpx.adobe.com/in/experience-mana...
I have usecase to create nested components using grid (column control) which loop over equal size cell , now each cell should have "drag component" aem parsys so that any component can be added.
So I want pointers for such example. Unfortunately, Adobe's doc's are unclear for this usecase.
Can you help ?
If you need any further sharing of code leme know or any other pointers.
Thnaks in advance
Hi, I would definitely need more information. What does exactly not work for you. Column control implements a parsys or responsivegrid component inside of each partition, so to speak. You should have a policy defining the components allowed in that container.
That where I need help to refer some example.
Do you have this code somewhere I could see? Like in a public repo?
give me 1 hr , leme clone the repo and remove internal stuff before sharing.
github -> @anfibiacreativa
Here you go: github.com/pgangwani/aem-react-pre...
Pl check column control: It should include childcomponents as added in comment
Added you as collaborator , can push directly if you found any thing fishy or small mistake
Hello Natalia, did you get chance to check the code ?
Hi :) No, it may take a bit. Unfortunately, it is a week with a lot of work for me ;)Thanks for being patient.
Thanks for letting me know. I can wait... :)
Hello Natalia, were you able to access the code
Hi Pawan. Today I had a little time to quickly take a look but your issue is not with AEM per se (as this article describes a modern yet independent to AEM Frontend Setup) but with the React implementation in the context of AEM SPA editor. So I am not sure I can help there. According to this npmjs.com/package/@adobe/cq-react-... You should be extending ResponsiveGrid and implementing something like { super.childComponents } inside of your div.
"Container.childComponents()
Returns the child components of this Container. It will iterate over all the items and instantiate the child components if a Mapping is found Instantiation is done my connecting the Component with the data of that item"
I tried that too , didn't work. Do you have AEM 6.5 ? Can you try and share the screen shot of console of printing child components. When I checked I got empty array. π
@pgangwani Do you have any update on this Usecase, I have tried the same and getting CQItems as empty array, when I try to use Model to get dialog values. Please let me know if you have solution on this. thanks in advance!!
Nice to see some AEM content on dev.to!!! Way to go!
Iβve contemplated posting AEM content here, but I always stop at the fact that there might not be an audience for it... plus I write most of that stuff on my employerβs site :)
Anyway! Awesome post! And would love to see more!!
Thank you. Second part, where I explain the actual webpack config and maven integration, coming next. :)
Ah, you should make use of this: dev.to/ben/changelog-create-series...
We are using native JavaScript and es6 features.
Page renders on server and only dynamic events are handled at front-end. Which is mostly static and is rendered on server. what folder structure we have to follow. pls do let me know
Very good article! Very well articulated.
Thank you. Part II is almost ready, so stay tuned!